Merge "Revert "Update clearData flow for notification settings"" into qt-dev
diff --git a/api/current.txt b/api/current.txt
index 6253dfd..1623bb8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8988,8 +8988,8 @@
     method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[], byte[]);
     method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[]);
     method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[], byte[]);
-    method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid);
-    method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+    method @NonNull public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(@Nullable android.os.ParcelUuid);
+    method @NonNull public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(@Nullable android.os.ParcelUuid, @Nullable android.os.ParcelUuid);
     method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid);
     method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
   }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 12474ce..68a8816 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -156,7 +156,7 @@
         KeyValuePairsAtom key_value_pairs_atom = 83 [(allow_from_any_uid) = true];
         VibratorStateChanged vibrator_state_changed = 84;
         DeferredJobStatsReported deferred_job_stats_reported = 85;
-        ThermalThrottlingStateChanged thermal_throttling = 86;
+        ThermalThrottlingStateChanged thermal_throttling = 86 [deprecated=true];
         BiometricAcquired biometric_acquired = 87;
         BiometricAuthenticated biometric_authenticated = 88;
         BiometricErrorOccurred biometric_error_occurred = 89;
@@ -270,7 +270,7 @@
         HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
         StyleUIChanged style_ui_changed = 179;
         PrivacyIndicatorsInteracted privacy_indicators_interacted =
-	    180 [(log_from_module) = "permissioncontroller"];
+            180 [(log_from_module) = "permissioncontroller"];
         AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
         NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"];
         AppMovedStorageReported app_moved_storage_reported = 183;
@@ -280,6 +280,7 @@
         BluetoothClassOfDeviceReported bluetooth_class_of_device_reported = 187;
         IntelligenceEventReported intelligence_event_reported =
             188 [(log_from_module) = "intelligence"];
+        ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189;
     }
 
     // Pulled events will start at field 10000.
@@ -409,6 +410,7 @@
  */
 
 /**
+ * This atom is deprecated starting in Q. Please use ThermalThrottlingSeverityStateChanged.
  * Logs when the Thermal service HAL notifies the throttling start/stop events.
  *
  * Logged from:
@@ -426,14 +428,7 @@
     }
     optional State state = 2;
 
-    // Temperature in deci degrees celsius
     optional float temperature = 3;
-
-    // Severity of throttling
-    optional android.os.ThrottlingSeverityEnum severity = 4;
-
-    // Thermistor name
-    optional string sensor_name = 5;
 }
 
 /**
@@ -2364,6 +2359,27 @@
 }
 
 /**
+ * Logs when ThermalService receives throttling events.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java
+ */
+message ThermalThrottlingSeverityStateChanged {
+    // The type of temperature being reported (CPU, GPU, SKIN, etc)
+    optional android.os.TemperatureTypeEnum sensor_type = 1;
+
+    // The name of the temperature source. Eg. CPU0
+    optional string sensor_name = 2;
+
+    // Temperature in tenths of a degree C.
+    // For BCL, it is decimillivolt, decimilliamps, and percentage * 10.
+    optional int32 temperature_deci_celsius = 3;
+
+    // Relative severity of the throttling, see enum definition.
+    optional android.os.ThrottlingSeverityEnum severity = 4;
+}
+
+/**
  * Logs the duration of a davey (jank of >=700ms) when it occurs
  *
  * Logged from:
diff --git a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
deleted file mode 100644
index 01c7587..0000000
--- a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include <sstream>
-#include "MemoryLeakTrackUtil.h"
-
-/*
- * The code here originally resided in MediaPlayerService.cpp
- */
-
-// Figure out the abi based on defined macros.
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__mips__) && !defined(__LP64__)
-#define ABI_STRING "mips"
-#elif defined(__mips__) && defined(__LP64__)
-#define ABI_STRING "mips64"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#else
-#error "Unsupported ABI"
-#endif
-
-extern std::string backtrace_string(const uintptr_t* frames, size_t frame_count);
-
-namespace android {
-namespace os {
-namespace statsd {
-
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, size_t* infoSize,
-                                     size_t* totalMemory, size_t* backtraceSize);
-
-extern "C" void free_malloc_leak_info(uint8_t* info);
-
-std::string dumpMemInfo(size_t limit) {
-    uint8_t* info;
-    size_t overallSize;
-    size_t infoSize;
-    size_t totalMemory;
-    size_t backtraceSize;
-    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
-
-    size_t count;
-    if (info == nullptr || overallSize == 0 || infoSize == 0 ||
-        (count = overallSize / infoSize) == 0) {
-        VLOG("no malloc info, libc.debug.malloc.program property should be set");
-        return std::string();
-    }
-
-    std::ostringstream oss;
-    oss << totalMemory << " bytes in " << count << " allocations\n";
-    oss << "  ABI: '" ABI_STRING "'"
-        << "\n\n";
-    if (count > limit) count = limit;
-
-    // The memory is sorted based on total size which is useful for finding
-    // worst memory offenders. For diffs, sometimes it is preferable to sort
-    // based on the backtrace.
-    for (size_t i = 0; i < count; i++) {
-        struct AllocEntry {
-            size_t size;  // bit 31 is set if this is zygote allocated memory
-            size_t allocations;
-            uintptr_t backtrace[];
-        };
-
-        const AllocEntry* const e = (AllocEntry*)(info + i * infoSize);
-
-        oss << (e->size * e->allocations) << " bytes ( " << e->size << " bytes * " << e->allocations
-            << " allocations )\n";
-        oss << backtrace_string(e->backtrace, backtraceSize) << "\n";
-    }
-    oss << "\n";
-    free_malloc_leak_info(info);
-    return oss.str();
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.h b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.h
deleted file mode 100644
index 444ed92..0000000
--- a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 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.
- */
-#pragma once
-
-#include <iostream>
-
-namespace android {
-namespace os {
-namespace statsd {
-/*
- * Dump the heap memory of the calling process, sorted by total size
- * (allocation size * number of allocations).
- *
- *    limit is the number of unique allocations to return.
- */
-extern std::string dumpMemInfo(size_t limit);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 86b10b9..0d22f3a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -773,6 +773,8 @@
     private static final int LOG_AM_ON_RESTART_CALLED = 30058;
     private static final int LOG_AM_ON_DESTROY_CALLED = 30060;
     private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062;
+    private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
+    private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
 
     private static class ManagedDialog {
         Dialog mDialog;
@@ -1840,6 +1842,13 @@
     public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
     }
 
+    final void performTopResumedActivityChanged(boolean isTopResumedActivity, String reason) {
+        onTopResumedActivityChanged(isTopResumedActivity);
+
+        writeEventLog(isTopResumedActivity
+                ? LOG_AM_ON_TOP_RESUMED_GAINED_CALLED : LOG_AM_ON_TOP_RESUMED_LOST_CALLED, reason);
+    }
+
     void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
         if (mVoiceInteractor != null) {
             for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 474f25b..13add09 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4026,7 +4026,7 @@
             r.persistentState = null;
             r.setState(ON_RESUME);
 
-            reportTopResumedActivityChanged(r, r.isTopResumedActivity);
+            reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
         } catch (Exception e) {
             if (!mInstrumentation.onException(r.activity, e)) {
                 throw new RuntimeException("Unable to resume activity "
@@ -4201,7 +4201,7 @@
         r.isTopResumedActivity = onTop;
 
         if (r.getLifecycleState() == ON_RESUME) {
-            reportTopResumedActivityChanged(r, onTop);
+            reportTopResumedActivityChanged(r, onTop, "topStateChangedWhenResumed");
         } else {
             if (DEBUG_ORDER) {
                 Slog.d(TAG, "Won't deliver top position change in state=" + r.getLifecycleState());
@@ -4213,10 +4213,11 @@
      * Call {@link Activity#onTopResumedActivityChanged(boolean)} if its top resumed state changed
      * since the last report.
      */
-    private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop) {
+    private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop,
+            String reason) {
         if (r.lastReportedTopResumedState != onTop) {
             r.lastReportedTopResumedState = onTop;
-            r.activity.onTopResumedActivityChanged(onTop);
+            r.activity.performTopResumedActivityChanged(onTop, reason);
         }
     }
 
@@ -4313,7 +4314,7 @@
 
         // Always reporting top resumed position loss when pausing an activity. If necessary, it
         // will be restored in performResumeActivity().
-        reportTopResumedActivityChanged(r, false /* onTop */);
+        reportTopResumedActivityChanged(r, false /* onTop */, "pausing");
 
         try {
             r.activity.mCalled = false;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0c6c77f..d0361b7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3165,8 +3165,8 @@
     /**
      * Gets the {@link LocusId} associated with this notification.
      *
-     * <p>Used by the device's intelligence services to correlate objects (such as
-     * {@link ShortcutInfo} and {@link ContentCaptureContext}) that are correlated.
+     * <p>Used by the Android system to correlate objects (such as
+     * {@link ShortcutInfo} and {@link ContentCaptureContext}).
      */
     @Nullable
     public LocusId getLocusId() {
@@ -3534,8 +3534,8 @@
          * Sets the {@link LocusId} associated with this notification.
          *
          * <p>This method should be called when the {@link LocusId} is used in other places (such
-         * as {@link ShortcutInfo} and {@link ContentCaptureContext}) so the device's intelligence
-         * services can correlate them.
+         * as {@link ShortcutInfo} and {@link ContentCaptureContext}) so the Android system can
+         * correlate them.
          */
         @NonNull
         public Builder setLocusId(@Nullable LocusId locusId) {
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 78140cf..07ba2c6 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -16,6 +16,7 @@
 
 package android.bluetooth.le;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -586,7 +587,8 @@
         /**
          * Set filter on service solicitation uuid.
          */
-        public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid) {
+        public @NonNull Builder setServiceSolicitationUuid(
+                @Nullable ParcelUuid serviceSolicitationUuid) {
             mServiceSolicitationUuid = serviceSolicitationUuid;
             return this;
         }
@@ -601,8 +603,9 @@
          * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but
          *             {@code serviceSolicitationUuidMask} is not {@code null}.
          */
-        public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid,
-                ParcelUuid solicitationUuidMask) {
+        public @NonNull Builder setServiceSolicitationUuid(
+                @Nullable ParcelUuid serviceSolicitationUuid,
+                @Nullable ParcelUuid solicitationUuidMask) {
             if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) {
                 throw new IllegalArgumentException(
                         "SolicitationUuid is null while SolicitationUuidMask is not null!");
diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java
index 283cea0..613765f 100644
--- a/core/java/android/content/LocusId.java
+++ b/core/java/android/content/LocusId.java
@@ -29,9 +29,8 @@
  * backup / restore.
  *
  * <p>Locus is a new concept introduced on
- * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the intelligence service provided
- * by the Android System to correlate state between different subsystems such as content capture,
- * shortcuts, and notifications.
+ * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the Android system correlate
+ * state between different subsystems such as content capture, shortcuts, and notifications.
  *
  * <p>For example, if your app provides an activiy representing a chat between 2 users
  * (say {@code A} and {@code B}, this chat state could be represented by:
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0ea5200..1784d8a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -8447,6 +8447,20 @@
         // Collect certificates
         if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
             collectCertificates(p, apexFile, false);
+            // Keep legacy mechanism for handling signatures. While this is deprecated, it's
+            // still part of the public API and needs to be maintained
+            if (p.mSigningDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Return
+                // the oldest cert so that programmatic checks keep working even if unaware
+                // of key rotation.
+                pi.signatures = new Signature[1];
+                pi.signatures[0] = p.mSigningDetails.pastSigningCertificates[0];
+            } else if (p.mSigningDetails.hasSignatures()) {
+                // otherwise keep old behavior
+                int numberOfSigs = p.mSigningDetails.signatures.length;
+                pi.signatures = new Signature[numberOfSigs];
+                System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
+            }
             if (p.mSigningDetails != SigningDetails.UNKNOWN) {
                 // only return a valid SigningInfo if there is signing information to report
                 pi.signingInfo = new SigningInfo(p.mSigningDetails);
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 1f82fa6..41be38a 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -991,8 +991,8 @@
          * Sets the {@link LocusId} associated with this shortcut.
          *
          * <p>This method should be called when the {@link LocusId} is used in other places (such
-         * as {@link Notification} and {@link ContentCaptureContext}) so the device's intelligence
-         * services can correlate them.
+         * as {@link Notification} and {@link ContentCaptureContext}) so the Android system can
+         * correlate them.
          */
         @NonNull
         public Builder setLocusId(@NonNull LocusId locusId) {
@@ -1325,8 +1325,8 @@
     /**
      * Gets the {@link LocusId} associated with this shortcut.
      *
-     * <p>Used by the device's intelligence services to correlate objects (such as
-     * {@link Notification} and {@link ContentCaptureContext}) that are correlated.
+     * <p>Used by the Android system to correlate objects (such as
+     * {@link Notification} and {@link ContentCaptureContext}).
      */
     @Nullable
     public LocusId getLocusId() {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6c498c7..9215de1 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -267,6 +267,13 @@
     public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider";
 
     /**
+     * Namespace for settings ui related features
+     *
+     * @hide
+     */
+    public static final String NAMESPACE_SETTINGS_UI = "settings_ui";
+
+    /**
      * List of namespaces which can be read without READ_DEVICE_CONFIG permission
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 83dc39e..ac59101 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12666,6 +12666,45 @@
         public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
 
         /**
+         * A long value indicating how much longer the system battery is estimated to last in
+         * millis. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value
+         * was updated.
+         *
+         * @hide
+         */
+        public static final String TIME_REMAINING_ESTIMATE_MILLIS =
+                "time_remaining_estimate_millis";
+
+        /**
+         * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is based customized
+         * to the devices usage or using global models. See
+         * {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value was updated.
+         *
+         * @hide
+         */
+        public static final String TIME_REMAINING_ESTIMATE_BASED_ON_USAGE =
+                "time_remaining_estimate_based_on_usage";
+
+        /**
+         * A long value indicating how long the system battery takes to deplete from 100% to 0% on
+         * average based on historical drain rates. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME}
+         * for the last time this value was updated.
+         *
+         * @hide
+         */
+        public static final String AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge";
+
+        /**
+         * A long indicating the epoch time in milliseconds when
+         * {@link #TIME_REMAINING_ESTIMATE_MILLIS}, {@link #TIME_REMAINING_ESTIMATE_BASED_ON_USAGE},
+         * and {@link #AVERAGE_TIME_TO_DISCHARGE} were last updated.
+         *
+         * @hide
+         */
+        public static final String BATTERY_ESTIMATES_LAST_UPDATE_TIME =
+                "battery_estimates_last_update_time";
+
+        /**
          * The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting is not set
          * or the value is 0, the default max will be used.
          *
@@ -13531,6 +13570,28 @@
         private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Overrides internal R.integer.config_longPressOnPowerBehavior.
+         * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+         * Used by PhoneWindowManager.
+         * @hide
+         */
+        public static final String POWER_BUTTON_LONG_PRESS =
+                "power_button_long_press";
+        private static final Validator POWER_BUTTON_LONG_PRESS_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 5);
+
+        /**
+         * Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
+         * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+         * Used by PhoneWindowManager.
+         * @hide
+         */
+        public static final String POWER_BUTTON_VERY_LONG_PRESS =
+                "power_button_very_long_press";
+        private static final Validator POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 1);
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
@@ -13643,6 +13704,8 @@
                     WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR);
             VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR);
             VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR);
+            VALIDATORS.put(POWER_BUTTON_LONG_PRESS, POWER_BUTTON_LONG_PRESS_VALIDATOR);
+            VALIDATORS.put(POWER_BUTTON_VERY_LONG_PRESS, POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR);
         }
 
         /**
@@ -14648,6 +14711,7 @@
          */
         public static final String TEXT_CLASSIFIER_ACTION_MODEL_PARAMS =
                 "text_classifier_action_model_params";
+
     }
 
     /**
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 94e548f..1692051 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -261,6 +261,7 @@
          *   example).
          *   <li>A unique identifier of the application state (for example, a conversation between
          *   2 users in a chat app).
+         * </ul>
          *
          * <p>See {@link ContentCaptureManager} for more info about the content capture context.
          *
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 26454c0..a977073 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -29,7 +29,6 @@
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
-import android.graphics.Canvas;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -51,61 +50,61 @@
 import java.util.Set;
 
 /**
- * <p>The {@link ContentCaptureManager} provides additional ways for for apps to
- * integrate with the content capture subsystem.
+ * Content capture is mechanism used to let apps notify the Android system of events associated with
+ * views.
  *
- * <p>Content capture provides real-time, continuous capture of application activity, display and
- * events to an intelligence service that is provided by the Android system. The intelligence
- * service then uses that info to mediate and speed user journey through different apps. For
- * example, when the user receives a restaurant address in a chat app and switchs to a map app
- * to search for that restaurant, the intelligence service could offer an autofill dialog to
- * let the user automatically select its address.
- *
- * <p>Content capture was designed with two major concerns in mind: privacy and performance.
- *
- * <ul>
- *   <li><b>Privacy:</b> the intelligence service is a trusted component provided that is provided
- *   by the device manufacturer and that cannot be changed by the user (although the user can
- *   globaly disable content capture using the Android Settings app). This service can only use the
- *   data for in-device machine learning, which is enforced both by process isolation and
- *   <a href="https://source.android.com/compatibility/cdd">CDD requirements</a>.
- *   <li><b>Performance:</b> content capture is highly optimized to minimize its impact in the app
- *   jankiness and overall device system health. For example, its only enabled on apps (or even
- *   specific activities from an app) that were explicitly whitelisted by the intelligence service,
- *   and it buffers the events so they are sent in a batch to the service (see
- *   {@link #isContentCaptureEnabled()} for other cases when its disabled).
- * </ul>
- *
- * <p>In fact, before using this manager, the app developer should check if it's available. Example:
- *  <code>
+ * <p>Before using this manager, you should check if it's available. Example:
+ * <pre><code>
  *  ContentCaptureManager mgr = context.getSystemService(ContentCaptureManager.class);
  *  if (mgr != null && mgr.isContentCaptureEnabled()) {
  *    // ...
  *  }
- *  </code>
+ *  </code></pre>
  *
- * <p>App developers usually don't need to explicitly interact with content capture, except when the
- * app:
+ * <p>To support content capture, you must notifiy the Android system of the following events:
  *
  * <ul>
- *   <li>Can define a contextual {@link android.content.LocusId} to identify unique state (such as a
- *   conversation between 2 chat users).
- *   <li>Can have multiple view hierarchies with different contextual meaning (for example, a
- *   browser app with multiple tabs, each representing a different URL).
- *   <li>Contains custom views (that extend View directly and are not provided by the standard
- *   Android SDK.
- *   <li>Contains views that provide their own virtual hierarchy (like a web browser that render the
- *   HTML elements using a Canvas).
+ *   <li>When a visible view is laid out, call
+ *   {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}.
+ *   <li>When a view becomes invisible or is removed from the view hierarchy, call
+ *   {@link ContentCaptureSession#notifyViewDisappeared(android.view.autofill.AutofillId)}.
+ *   <li>When the view represents text and the text value changed, call {@link
+ *   ContentCaptureSession#notifyViewTextChanged(android.view.autofill.AutofillId, CharSequence)}.
  * </ul>
  *
+ * <p>You can get a blank content capture structure using
+ * {@link ContentCaptureSession#newViewStructure(View)}, then populate its relevant fields.
+ * Here's an example of the relevant methods for an {@code EditText}-like view:
+ *
+ * <pre><code>
+ * public class MyEditText extends View {
+ *
+ * private void populateContentCaptureStructure(@NonNull ViewStructure structure) {
+ *   structure.setText(getText(), getSelectionStart(), getSelectionEnd());
+ *   structure.setHint(getHint());
+ *   structure.setInputType(getInputType());
+ *   // set other properties like setTextIdEntry(), setTextLines(), setTextStyle(),
+ *   // setMinTextEms(), setMaxTextEms(), setMaxTextLength()
+ * }
+ *
+ * private void onTextChanged() {
+ *   if (isLaidOut() && isTextEditable()) {
+ *     ContentCaptureManager mgr = mContext.getSystemService(ContentCaptureManager.class);
+ *     if (cm != null && cm.isContentCaptureEnabled()) {
+ *        ContentCaptureSession session = getContentCaptureSession();
+ *        if (session != null) {
+ *          session.notifyViewTextChanged(getAutofillId(), getText());
+ *        }
+ *   }
+ * }
+ * </code></pre>
+ *
  * <p>The main integration point with content capture is the {@link ContentCaptureSession}. A "main"
- * session is automatically created by the Android System when content capture is enabled for the
- * activity and its used by the standard Android views to notify the content capture service of
- * events such as views being added, views been removed, and text changed by user input. The session
- * could have a {@link ContentCaptureContext} to provide more contextual info about it, such as
- * the locus associated with the view hierarchy (see {@link android.content.LocusId} for more info
- * about locus). By default, the main session doesn't have a {@code ContentCaptureContext}, but you
- * can change it after its created. Example:
+ * session is automatically created by the Android system when content capture is enabled for the
+ * activity. The session could have a {@link ContentCaptureContext} to provide more contextual info
+ * about it, such as the locus associated with the view hierarchy
+ * (see {@link android.content.LocusId} for more info about locus). By default, the main session
+ * doesn't have a {@code ContentCaptureContext}, but you can change it after its created. Example:
  *
  * <pre><code>
  * protected void onCreate(Bundle savedInstanceState) {
@@ -145,54 +144,6 @@
  * }
  * </code></pre>
  *
- * <p>If your activity has custom views (i.e., views that extend {@link View} directly and provide
- * just one logical view, not a virtual tree hiearchy) and it provides content that's relevant for
- * content capture (as of {@link android.os.Build.VERSION_CODES#Q Android Q}, the only relevant
- * content is text), then your view implementation should:
- *
- * <ul>
- *   <li>Set it as important for content capture.
- *   <li>Fill {@link ViewStructure} used for content capture.
- *   <li>Notify the {@link ContentCaptureSession} when the text is changed by user input.
- * </ul>
- *
- * <p>Here's an example of the relevant methods for an {@code EditText}-like view:
- *
- * <pre><code>
- * public class MyEditText extends View {
- *
- * public MyEditText(...) {
- *   if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
- *     setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES);
- *   }
- * }
- *
- * public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
- *   super.onProvideContentCaptureStructure(structure, flags);
- *
- *   structure.setText(getText(), getSelectionStart(), getSelectionEnd());
- *   structure.setHint(getHint());
- *   structure.setInputType(getInputType());
- *   // set other properties like setTextIdEntry(), setTextLines(), setTextStyle(),
- *   // setMinTextEms(), setMaxTextEms(), setMaxTextLength()
- * }
- *
- * private void onTextChanged() {
- *   if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) {
- *     ContentCaptureManager mgr = mContext.getSystemService(ContentCaptureManager.class);
- *     if (cm != null && cm.isContentCaptureEnabled()) {
- *        ContentCaptureSession session = getContentCaptureSession();
- *        if (session != null) {
- *          session.notifyViewTextChanged(getAutofillId(), getText());
- *        }
- *   }
- * }
- * </code></pre>
- *
- * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws
- * the HTML using {@link Canvas} or native libraries in a different render process), then the view
- * is also responsible to notify the session when the virtual elements appear and disappear -
- * see {@link ContentCaptureSession#newViewStructure(View)} for more info.
  */
 @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
 public final class ContentCaptureManager {
@@ -473,17 +424,6 @@
 
     /**
      * Checks whether content capture is enabled for this activity.
-     *
-     * <p>There are many reasons it could be disabled, such as:
-     * <ul>
-     *   <li>App itself disabled content capture through {@link #setContentCaptureEnabled(boolean)}.
-     *   <li>Intelligence service did not whitelist content capture for this activity's package.
-     *   <li>Intelligence service did not whitelist content capture for this specific activity.
-     *   <li>Intelligence service disabled content capture globally.
-     *   <li>User disabled content capture globally through the Android Settings app.
-     *   <li>Device manufacturer (OEM) disabled content capture globally.
-     *   <li>Transient errors, such as intelligence service package being updated.
-     * </ul>
      */
     public boolean isContentCaptureEnabled() {
         if (mOptions.lite) return false;
@@ -503,9 +443,9 @@
      * Gets the list of conditions for when content capture should be allowed.
      *
      * <p>This method is typically used by web browsers so they don't generate unnecessary content
-     * capture events for websites the content capture service is not interested on.
+     * capture events for some websites.
      *
-     * @return list of conditions, or {@code null} if the service didn't set any restriction
+     * @return list of conditions, or {@code null} if there isn't any restriction
      * (in which case content capture events should always be generated). If the list is empty,
      * then it should not generate any event at all.
      */
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 17a1fb4..210dea1 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -41,8 +41,7 @@
 import java.util.Random;
 
 /**
- * Session used to notify a system-provided Content Capture service about events associated with
- * views.
+ * Session used to notify the Android system about events associated with views.
  */
 public abstract class ContentCaptureSession implements AutoCloseable {
 
@@ -306,7 +305,7 @@
     }
 
     /**
-     * Destroys this session, flushing out all pending notifications to the service.
+     * Destroys this session, flushing out all pending notifications.
      *
      * <p>Once destroyed, any new notification will be dropped.
      */
@@ -354,7 +353,7 @@
     }
 
     /**
-     * Notifies the Content Capture Service that a node has been added to the view structure.
+     * Notifies the Android system that a node has been added to the view structure.
      *
      * @param node node that has been added.
      */
@@ -372,7 +371,7 @@
     abstract void internalNotifyViewAppeared(@NonNull ViewNode.ViewStructureImpl node);
 
     /**
-     * Notifies the Content Capture Service that a node has been removed from the view structure.
+     * Notifies the Android system that a node has been removed from the view structure.
      *
      * @param id id of the node that has been removed.
      */
@@ -386,7 +385,7 @@
     abstract void internalNotifyViewDisappeared(@NonNull AutofillId id);
 
     /**
-     * Notifies the Content Capture Service that many nodes has been removed from a virtual view
+     * Notifies the Android system that many nodes has been removed from a virtual view
      * structure.
      *
      * <p>Should only be called by views that handle their own virtual view hierarchy.
@@ -412,7 +411,7 @@
     }
 
     /**
-     * Notifies the Intelligence Service that the value of a text node has been changed.
+     * Notifies the Android system that the value of a text node has been changed.
      *
      * @param id of the node.
      * @param text new text.
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 59e867f..8380115 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -200,7 +200,6 @@
 
     private ChooserListAdapter mChooserListAdapter;
     private ChooserRowAdapter mChooserRowAdapter;
-    private Drawable mChooserRowLayer;
     private int mChooserRowServiceSpacing;
 
     /** {@link ChooserActivity#getBaseScore} */
@@ -219,6 +218,8 @@
     private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 4;
     private static final int LIST_VIEW_UPDATE_MESSAGE = 5;
 
+    private static final int MAX_LOG_RANK_POSITION = 12;
+
     @VisibleForTesting
     public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
 
@@ -466,7 +467,6 @@
                 .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback);
         }
 
-        mChooserRowLayer = getResources().getDrawable(R.drawable.chooser_row_layer_list, null);
         mChooserRowServiceSpacing = getResources()
                                         .getDimensionPixelSize(R.dimen.chooser_service_spacing);
 
@@ -1015,6 +1015,7 @@
             // Lower values mean the ranking was better.
             int cat = 0;
             int value = which;
+            int directTargetAlsoRanked = -1;
             HashedStringCache.HashResult directTargetHashed = null;
             switch (mChooserListAdapter.getPositionTargetType(which)) {
                 case ChooserListAdapter.TARGET_CALLER:
@@ -1034,6 +1035,7 @@
                             target.getComponentName().getPackageName()
                                     + target.getTitle().toString(),
                             mMaxHashSaltDays);
+                    directTargetAlsoRanked = getRankedPosition((SelectableTargetInfo) targetInfo);
                     break;
                 case ChooserListAdapter.TARGET_STANDARD:
                     cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
@@ -1056,6 +1058,8 @@
                     targetLogMaker.addTaggedData(
                                     MetricsEvent.FIELD_HASHED_TARGET_SALT_GEN,
                                     directTargetHashed.saltGeneration);
+                    targetLogMaker.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION,
+                                    directTargetAlsoRanked);
                 }
                 getMetricsLogger().write(targetLogMaker);
                 MetricsLogger.action(this, cat, value);
@@ -1074,6 +1078,21 @@
         }
     }
 
+    private int getRankedPosition(SelectableTargetInfo targetInfo) {
+        String targetPackageName =
+                targetInfo.getChooserTarget().getComponentName().getPackageName();
+        int maxRankedResults = Math.min(mChooserListAdapter.mDisplayList.size(),
+                        MAX_LOG_RANK_POSITION);
+
+        for (int i = 0; i < maxRankedResults; i++) {
+            if (mChooserListAdapter.mDisplayList.get(i)
+                    .getResolveInfo().activityInfo.packageName.equals(targetPackageName)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     void queryTargetServices(ChooserListAdapter adapter) {
         final PackageManager pm = getPackageManager();
         ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class);
@@ -1931,6 +1950,7 @@
 
                 int offset = 0;
                 int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
+                        + mChooserRowAdapter.getProfileRowCount()
                         + mChooserRowAdapter.getServiceTargetRowCount()
                         + mChooserRowAdapter.getCallerAndRankedTargetRowCount();
 
@@ -1950,7 +1970,7 @@
                 }
 
                 int lastHeight = 0;
-                rowsToShow = Math.max(3, rowsToShow);
+                rowsToShow = Math.min(4, rowsToShow);
                 for (int i = 0; i < Math.min(rowsToShow, mAdapterView.getChildCount()); i++) {
                     lastHeight = mAdapterView.getChildAt(i).getHeight();
                     offset += lastHeight;
@@ -2426,6 +2446,7 @@
         private static final int VIEW_TYPE_DIRECT_SHARE = 0;
         private static final int VIEW_TYPE_NORMAL = 1;
         private static final int VIEW_TYPE_CONTENT_PREVIEW = 2;
+        private static final int VIEW_TYPE_PROFILE = 3;
 
         private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
         private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
@@ -2481,9 +2502,9 @@
 
         @Override
         public int getCount() {
-
             return (int) (
                     getContentPreviewRowCount()
+                            + getProfileRowCount()
                             + getServiceTargetRowCount()
                             + getCallerAndRankedTargetRowCount()
                             + Math.ceil(
@@ -2504,6 +2525,10 @@
             return 1;
         }
 
+        public int getProfileRowCount() {
+            return mChooserListAdapter.getOtherProfile() == null ? 0 : 1;
+        }
+
         public int getCallerAndRankedTargetRowCount() {
             return (int) Math.ceil(
                     ((float) mChooserListAdapter.getCallerTargetCount()
@@ -2539,6 +2564,10 @@
                 return createContentPreviewView(convertView, parent);
             }
 
+            if (viewType == VIEW_TYPE_PROFILE) {
+                return createProfileView(convertView, parent);
+            }
+
             if (convertView == null) {
                 holder = createViewHolder(viewType, parent);
             } else {
@@ -2556,6 +2585,10 @@
                 return VIEW_TYPE_CONTENT_PREVIEW;
             }
 
+            if (getProfileRowCount() == 1 && position == getContentPreviewRowCount()) {
+                return VIEW_TYPE_PROFILE;
+            }
+
             final int start = getFirstRowPosition(position);
             final int startType = mChooserListAdapter.getPositionTargetType(start);
 
@@ -2568,7 +2601,7 @@
 
         @Override
         public int getViewTypeCount() {
-            return 3;
+            return 4;
         }
 
         private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) {
@@ -2584,6 +2617,17 @@
                     (ViewGroup) convertView, parent);
         }
 
+        private View createProfileView(View convertView, ViewGroup parent) {
+            View profileRow = convertView != null ? convertView : mLayoutInflater.inflate(
+                    R.layout.chooser_profile_row, parent, false);
+            profileRow.setBackground(
+                    getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
+            mProfileView = profileRow.findViewById(R.id.profile_button);
+            mProfileView.setOnClickListener(ChooserActivity.this::onProfileClick);
+            bindProfileView();
+            return profileRow;
+        }
+
         private RowViewHolder loadViewsIntoRow(RowViewHolder holder) {
             final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
             final int exactSpec = MeasureSpec.makeMeasureSpec(mChooserTargetWidth,
@@ -2702,8 +2746,10 @@
 
             final ViewGroup row = holder.getViewGroup();
 
-            if (startType != lastStartType || rowPosition == getContentPreviewRowCount()) {
-                row.setBackground(mChooserRowLayer);
+            if (startType != lastStartType
+                    || rowPosition == getContentPreviewRowCount() + getProfileRowCount()) {
+                row.setBackground(
+                        getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
             } else {
                 row.setBackground(null);
             }
@@ -2753,7 +2799,7 @@
         }
 
         int getFirstRowPosition(int row) {
-            row -= getContentPreviewRowCount();
+            row -= getContentPreviewRowCount() + getProfileRowCount();
 
             final int serviceCount = mChooserListAdapter.getServiceTargetCount();
             final int serviceRows = (int) Math.ceil((float) serviceCount
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ad1e767..2849f57 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -108,7 +108,7 @@
     private Button mAlwaysButton;
     private Button mOnceButton;
     private Button mSettingsButton;
-    private View mProfileView;
+    protected View mProfileView;
     private int mIconDpi;
     private int mLastSelected = AbsListView.INVALID_POSITION;
     private boolean mResolvingHome = false;
@@ -142,9 +142,7 @@
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override public void onSomePackagesChanged() {
             mAdapter.handlePackagesChanged();
-            if (mProfileView != null) {
-                bindProfileView();
-            }
+            bindProfileView();
         }
 
         @Override
@@ -336,21 +334,7 @@
 
         mProfileView = findViewById(R.id.profile_button);
         if (mProfileView != null) {
-            mProfileView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    final DisplayResolveInfo dri = mAdapter.getOtherProfile();
-                    if (dri == null) {
-                        return;
-                    }
-
-                    // Do not show the profile switch message anymore.
-                    mProfileSwitchMessageId = -1;
-
-                    onTargetSelected(dri, false);
-                    finish();
-                }
-            });
+            mProfileView.setOnClickListener(this::onProfileClick);
             bindProfileView();
         }
 
@@ -367,6 +351,19 @@
                         + (categories != null ? Arrays.toString(categories.toArray()) : ""));
     }
 
+    protected void onProfileClick(View v) {
+        final DisplayResolveInfo dri = mAdapter.getOtherProfile();
+        if (dri == null) {
+            return;
+        }
+
+        // Do not show the profile switch message anymore.
+        mProfileSwitchMessageId = -1;
+
+        onTargetSelected(dri, false);
+        finish();
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -445,7 +442,11 @@
         return R.layout.resolver_list;
     }
 
-    void bindProfileView() {
+    protected void bindProfileView() {
+        if (mProfileView == null) {
+            return;
+        }
+
         final DisplayResolveInfo dri = mAdapter.getOtherProfile();
         if (dri != null) {
             mProfileView.setVisibility(View.VISIBLE);
@@ -709,9 +710,7 @@
             mRegistered = true;
         }
         mAdapter.handlePackagesChanged();
-        if (mProfileView != null) {
-            bindProfileView();
-        }
+        bindProfileView();
     }
 
     @Override
@@ -1737,9 +1736,7 @@
                         @Override
                         protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
                             processSortedList(sortedComponents);
-                            if (mProfileView != null) {
-                                bindProfileView();
-                            }
+                            bindProfileView();
                             notifyDataSetChanged();
                         }
                     };
@@ -2148,7 +2145,7 @@
 
         @Override
         protected void onPostExecute(Drawable d) {
-            if (mProfileView != null && mAdapter.getOtherProfile() == mDisplayResolveInfo) {
+            if (mAdapter.getOtherProfile() == mDisplayResolveInfo) {
                 bindProfileView();
             } else {
                 mDisplayResolveInfo.setDisplayIcon(d);
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a7244a7..76826d3 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -19,7 +19,6 @@
 import android.annotation.CallSuper;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
@@ -266,17 +265,7 @@
         if (visibleFolder != null) {
             assert (visibleFolder.isDirectory());
 
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                final ContentResolver resolver = getContext().getContentResolver();
-                final Uri uri = MediaStore.Files.getDirectoryUri("external");
-                ContentValues values = new ContentValues();
-                values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
-                resolver.insert(uri, values);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+            MediaStore.scanFile(getContext(), visibleFolder);
         }
     }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 5fee2c9..8f8e4d8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -48,8 +48,7 @@
     void setIconVisibility(String slot, boolean visible);
     @UnsupportedAppUsage
     void removeIcon(String slot);
-    // TODO(b/117478341): support back button change when IME is showing on a external display.
-    void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+    void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
     void expandSettingsPanel(String subPanel);
 
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index d037d4b..bf088e0a 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -455,7 +455,7 @@
      * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
      */
     public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
-        if (color == Notification.COLOR_DEFAULT || defaultBackgroundIsDark) {
+        if (color == Notification.COLOR_DEFAULT) {
             int res = defaultBackgroundIsDark
                     ? com.android.internal.R.color.notification_default_color_dark
                     : com.android.internal.R.color.notification_default_color_light;
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index e22f581..076e99d 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -22,6 +22,9 @@
 #include <jni.h>
 #include "core_jni_helpers.h"
 
+#include <android-base/logging.h>
+#include <bionic_malloc.h>
+
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -30,11 +33,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
-                                     size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
-
-extern "C" void free_malloc_leak_info(uint8_t* info);
-
 #define DDMS_HEADER_SIGNATURE 0x812345dd
 #define DDMS_VERSION 2
 
@@ -78,9 +76,16 @@
     ReadFile("/proc/self/maps", maps);
     header.mapSize = maps.size();
 
-    uint8_t* allocBytes;
-    get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize,
-                         &header.totalMemory, &header.backtraceSize);
+    android_mallopt_leak_info_t leak_info;
+    if (!android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))) {
+      PLOG(ERROR) << "*** Failed to get malloc leak info";
+      return nullptr;
+    }
+
+    header.allocSize = leak_info.overall_size;
+    header.allocInfoSize = leak_info.info_size;
+    header.totalMemory = leak_info.total_memory;
+    header.backtraceSize = leak_info.backtrace_size;
 
     ALOGD("*** mapSize: %zu allocSize: %zu allocInfoSize: %zu totalMemory: %zu",
           header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
@@ -98,10 +103,10 @@
         env->SetByteArrayRegion(array, sizeof(header),
                                 maps.size(), reinterpret_cast<const jbyte*>(maps.string()));
         env->SetByteArrayRegion(array, sizeof(header) + maps.size(),
-                                header.allocSize, reinterpret_cast<jbyte*>(allocBytes));
+                                header.allocSize, reinterpret_cast<jbyte*>(leak_info.buffer));
     }
 
-    free_malloc_leak_info(allocBytes);
+    android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info));
     return array;
 }
 
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 1c247cb..7052ed6 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1008,9 +1008,11 @@
         double x, double y,
         const std::array<float, 6>& distortion,
         const float cx, const float cy, const float f,
-        int preCorrW, int preCorrH) {
+        const int preCorrW, const int preCorrH, const int xMin, const int yMin) {
     undistort(x, y, distortion, cx, cy, f);
-    if (x < 0.0 || y < 0.0 || x > preCorrW - 1 || y > preCorrH - 1) {
+    int xMax = xMin + preCorrW - 1;
+    int yMax = yMin + preCorrH - 1;
+    if (x < xMin || y < yMin || x > xMax || y > yMax) {
         return false;
     }
     return true;
@@ -1019,40 +1021,48 @@
 static inline bool boxWithinPrecorrectionArray(
         int left, int top, int right, int bottom,
         const std::array<float, 6>& distortion,
-        const float& cx, const float& cy, const float& f,
-        const int& preCorrW, const int& preCorrH){
+        const float cx, const float cy, const float f,
+        const int preCorrW, const int preCorrH, const int xMin, const int yMin){
     // Top row
-    if (!unDistortWithinPreCorrArray(left, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(left, top,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
-    if (!unDistortWithinPreCorrArray(cx, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(cx, top,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
-    if (!unDistortWithinPreCorrArray(right, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(right, top,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
     // Middle row
-    if (!unDistortWithinPreCorrArray(left, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(left, cy,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
-    if (!unDistortWithinPreCorrArray(right, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(right, cy,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
     // Bottom row
-    if (!unDistortWithinPreCorrArray(left, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(left, bottom,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
-    if (!unDistortWithinPreCorrArray(cx, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(cx, bottom,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
 
-    if (!unDistortWithinPreCorrArray(right, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+    if (!unDistortWithinPreCorrArray(right, bottom,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
         return false;
     }
     return true;
@@ -1062,7 +1072,8 @@
         double scale/*must be <= 1.0*/,
         const std::array<float, 6>& distortion,
         const float cx, const float cy, const float f,
-        const int preCorrW, const int preCorrH){
+        const int preCorrW, const int preCorrH,
+        const int xMin, const int yMin){
 
     double left = cx * (1.0 - scale);
     double right = (preCorrW - 1) * scale + cx * (1.0 - scale);
@@ -1070,14 +1081,14 @@
     double bottom = (preCorrH - 1) * scale + cy * (1.0 - scale);
 
     return boxWithinPrecorrectionArray(left, top, right, bottom,
-            distortion, cx, cy, f, preCorrW, preCorrH);
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin);
 }
 
 static status_t findPostCorrectionScale(
         double stepSize, double minScale,
         const std::array<float, 6>& distortion,
         const float cx, const float cy, const float f,
-        const int preCorrW, const int preCorrH,
+        const int preCorrW, const int preCorrH, const int xMin, const int yMin,
         /*out*/ double* outScale) {
     if (outScale == nullptr) {
         ALOGE("%s: outScale must not be null", __FUNCTION__);
@@ -1086,7 +1097,7 @@
 
     for (double scale = 1.0; scale > minScale; scale -= stepSize) {
         if (scaledBoxWithinPrecorrectionArray(
-                scale, distortion, cx, cy, f, preCorrW, preCorrH)) {
+                scale, distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
             *outScale = scale;
             return OK;
         }
@@ -1100,16 +1111,18 @@
 // are sampled within the precorrection array
 static void normalizeLensDistortion(
         /*inout*/std::array<float, 6>& distortion,
-        float cx, float cy, float f, int preCorrW, int preCorrH) {
-    ALOGV("%s: distortion [%f, %f, %f, %f, %f, %f], (cx,cy) (%f, %f), f %f, (W,H) (%d, %d)",
+        float cx, float cy, float f, int preCorrW, int preCorrH, int xMin = 0, int yMin = 0) {
+    ALOGV("%s: distortion [%f, %f, %f, %f, %f, %f], (cx,cy) (%f, %f), f %f, (W,H) (%d, %d)"
+            ", (xmin, ymin, xmax, ymax) (%d, %d, %d, %d)",
             __FUNCTION__, distortion[0], distortion[1], distortion[2],
             distortion[3], distortion[4], distortion[5],
-            cx, cy, f, preCorrW, preCorrH);
+            cx, cy, f, preCorrW, preCorrH,
+            xMin, yMin, xMin + preCorrW - 1, yMin + preCorrH - 1);
 
     // Only update distortion coeffients if we can find a good bounding box
     double scale = 1.0;
     if (OK == findPostCorrectionScale(0.002, 0.5,
-            distortion, cx, cy, f, preCorrW, preCorrH,
+            distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin,
             /*out*/&scale)) {
         ALOGV("%s: scaling distortion coefficients by %f", __FUNCTION__, scale);
         // The formula:
@@ -1216,6 +1229,8 @@
 
     sp<TiffWriter> writer = new TiffWriter();
 
+    uint32_t preXMin = 0;
+    uint32_t preYMin = 0;
     uint32_t preWidth = 0;
     uint32_t preHeight = 0;
     uint8_t colorFilter = 0;
@@ -1225,6 +1240,8 @@
         camera_metadata_entry entry =
                 characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
         BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
+        preXMin = static_cast<uint32_t>(entry.data.i32[0]);
+        preYMin = static_cast<uint32_t>(entry.data.i32[1]);
         preWidth = static_cast<uint32_t>(entry.data.i32[2]);
         preHeight = static_cast<uint32_t>(entry.data.i32[3]);
 
@@ -1966,9 +1983,16 @@
                     distortion[i+1] = entry3.data.f[i];
                 }
 
-                // TODO b/118690688: deal with the case where RAW size != preCorrSize
                 if (preWidth == imageWidth && preHeight == imageHeight) {
                     normalizeLensDistortion(distortion, cx, cy, f, preWidth, preHeight);
+                } else {
+                    // image size == pixel array size (contains optical black pixels)
+                    // cx/cy is defined in preCorrArray so adding the offset
+                    // Also changes default xmin/ymin so that pixels are only
+                    // sampled within preCorrection array
+                    normalizeLensDistortion(
+                            distortion, cx + preXMin, cy + preYMin, f, preWidth, preHeight,
+                            preXMin, preYMin);
                 }
 
                 float m_x = std::fmaxf(preWidth-1 - cx, cx);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 195fe58..69a7c4d 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,6 +33,8 @@
 #include <string>
 #include <vector>
 
+#include <android-base/logging.h>
+#include <bionic_malloc.h>
 #include <debuggerd/client.h>
 #include <log/log.h>
 #include <utils/misc.h>
@@ -663,9 +665,6 @@
     return true;
 }
 
-/* pulled out of bionic */
-extern "C" void write_malloc_leak_info(FILE* fp);
-
 /*
  * Dump the native heap, writing human-readable output to the specified
  * file descriptor.
@@ -681,8 +680,11 @@
     ALOGD("Native heap dump starting...\n");
     // Formatting of the native heap dump is handled by malloc debug itself.
     // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format
-    write_malloc_leak_info(fp.get());
-    ALOGD("Native heap dump complete.\n");
+    if (android_mallopt(M_WRITE_MALLOC_LEAK_INFO_TO_FILE, fp.get(), sizeof(FILE*))) {
+      ALOGD("Native heap dump complete.\n");
+    } else {
+      PLOG(ERROR) << "Failed to write native heap dump to file";
+    }
 }
 
 /*
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 68c62a6..138e24e3 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -41,21 +41,6 @@
             android:layout_centerHorizontal="true"
             android:layout_alignParentTop="true" />
 
-        <TextView android:id="@+id/profile_button"
-                  android:layout_width="wrap_content"
-                  android:layout_height="48dp"
-                  android:layout_marginEnd="8dp"
-                  android:paddingStart="8dp"
-                  android:paddingEnd="8dp"
-                  android:visibility="gone"
-                  style="?attr/borderlessButtonStyle"
-                  android:textAppearance="?attr/textAppearanceButton"
-                  android:textColor="?attr/colorAccent"
-                  android:gravity="center_vertical"
-                  android:layout_below="@id/drag"
-                  android:layout_alignParentRight="true"
-                  android:singleLine="true"/>
-
         <TextView android:id="@+id/title"
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
@@ -67,7 +52,7 @@
                   android:paddingBottom="@dimen/chooser_view_spacing"
                   android:paddingLeft="24dp"
                   android:paddingRight="24dp"
-                  android:layout_below="@id/profile_button"
+                  android:layout_below="@id/drag"
                   android:layout_centerHorizontal="true"/>
     </RelativeLayout>
 
diff --git a/core/res/res/layout/chooser_profile_row.xml b/core/res/res/layout/chooser_profile_row.xml
new file mode 100644
index 0000000..1a24a07
--- /dev/null
+++ b/core/res/res/layout/chooser_profile_row.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:gravity="center">
+  <TextView
+      android:id="@+id/profile_button"
+      android:layout_width="wrap_content"
+      android:layout_height="48dp"
+      style="?attr/borderlessButtonStyle"
+      android:textAppearance="?attr/textAppearanceButton"
+      android:textColor="?attr/colorAccent"
+      android:singleLine="true"/>
+</LinearLayout>
+
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9c4717b..b3e94e3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1098,6 +1098,7 @@
             2 - Power off (with confirmation)
             3 - Power off (without confirmation)
             4 - Go to voice assist
+            5 - Go to assistant (Settings.Secure.ASSISTANT)
     -->
     <integer name="config_longPressOnPowerBehavior">1</integer>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a6a0c6e..2f34c94 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2794,6 +2794,7 @@
   <java-symbol type="drawable" name="scroll_indicator_material" />
 
   <java-symbol type="layout" name="chooser_row" />
+  <java-symbol type="layout" name="chooser_profile_row" />
   <java-symbol type="color" name="chooser_row_divider" />
   <java-symbol type="layout" name="chooser_row_direct_share" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0e94abc0..a853121 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -130,8 +130,10 @@
                     Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
                     Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
                     Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+                    Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
                     Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
+                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
                     Settings.Global.BROADCAST_BG_CONSTANTS,
                     Settings.Global.BROADCAST_FG_CONSTANTS,
                     Settings.Global.BROADCAST_OFFLOAD_CONSTANTS,
@@ -462,6 +464,8 @@
                     Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS,
                     Settings.Global.THEATER_MODE_ON,
                     Settings.Global.TIME_ONLY_MODE_CONSTANTS,
+                    Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS,
+                    Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE,
                     Settings.Global.TRANSITION_ANIMATION_SCALE,
                     Settings.Global.TRUSTED_SOUND,
                     Settings.Global.TZINFO_UPDATE_CONTENT_URL,
@@ -573,7 +577,10 @@
                     Settings.Global.RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD,
                     Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD,
                     Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT,
-                    Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT);
+                    Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT,
+                    Settings.Global.POWER_BUTTON_LONG_PRESS,
+                    Settings.Global.POWER_BUTTON_VERY_LONG_PRESS);
+
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
                  Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
diff --git a/core/tests/coretests/src/android/util/HashedStringCacheTest.java b/core/tests/coretests/src/android/util/HashedStringCacheTest.java
index 333db24..2292473 100644
--- a/core/tests/coretests/src/android/util/HashedStringCacheTest.java
+++ b/core/tests/coretests/src/android/util/HashedStringCacheTest.java
@@ -80,6 +80,17 @@
         assertThat(cachedResult2.hashedString, is(cachedResult.hashedString));
     }
 
+
+    @Test
+    public void testThatMultipleInputResultInDifferentHash() {
+        HashedStringCache cache = HashedStringCache.getInstance();
+        HashedStringCache.HashResult cachedResult =
+                cache.hashString(mContext, TAG, TEST_STRING, 7);
+        HashedStringCache.HashResult cachedResult2 =
+                cache.hashString(mContext, TAG, "different_test", 7);
+        assertThat(cachedResult2.hashedString, is(not(cachedResult.hashedString)));
+    }
+
     @Test
     public void testThatZeroDaysResultsInNewHash() {
         HashedStringCache cache = HashedStringCache.getInstance();
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index ac039dd..767ec0e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -18,6 +18,7 @@
 
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
@@ -62,9 +63,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.function.Function;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -74,7 +72,10 @@
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
+import java.util.function.Function;
 
 /**
  * Chooser activity instrumentation tests
@@ -245,7 +246,7 @@
         waitForIdle();
 
         assertThat(activity.getAdapter().getCount(), is(2));
-        onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.profile_button)).check(doesNotExist());
 
         ResolveInfo[] chosen = new ResolveInfo[1];
         sOverrides.onSafelyStartCallback = targetInfo -> {
@@ -770,8 +771,6 @@
     }
 
     // This test is too long and too slow and should not be taken as an example for future tests.
-    // This is necessary because it tests that multiple calls result in the same result but
-    // normally a test this long should be broken into smaller tests testing individual components.
     @Test
     public void testDirectTargetSelectionLogging() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
@@ -785,7 +784,7 @@
         MetricsLogger mockLogger = sOverrides.metricsLogger;
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
         // Create direct share target
-        List<ChooserTarget> serviceTargets = createDirectShareTargets(1);
+        List<ChooserTarget> serviceTargets = createDirectShareTargets(1, "");
         ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);
 
         // Start activity
@@ -808,7 +807,7 @@
         // TODO: restructure the tests b/129870719
         Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
 
-        assertThat("Chooser should have 3 targets (2apps, 1 direct)",
+        assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
                 activity.getAdapter().getCount(), is(3));
         assertThat("Chooser should have exactly one selectable direct target",
                 activity.getAdapter().getSelectableServiceTargetCount(), is(1));
@@ -832,20 +831,36 @@
                 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
         assertThat("Hash is not predictable but must be obfuscated",
                 hashedName, is(not(name)));
+        assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
+                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
+    }
 
-        // Running the same again to check if the hashed name is the same as before.
+    // This test is too long and too slow and should not be taken as an example for future tests.
+    @Test
+    public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException {
+        Intent sendIntent = createSendTextIntent();
+        // We need app targets for direct targets to get displayed
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
 
-        Intent sendIntent2 = createSendTextIntent();
+        // Set up resources
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        // Create direct share target
+        List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
+                resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
+        ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);
 
         // Start activity
-        final ChooserWrapperActivity activity2 = mActivityRule
-                .launchActivity(Intent.createChooser(sendIntent2, null));
-        waitForIdle();
+        final ChooserWrapperActivity activity = mActivityRule
+                .launchActivity(Intent.createChooser(sendIntent, null));
 
         // Insert the direct share target
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                () -> activity2.getAdapter().addServiceResults(
-                        activity2.createTestDisplayResolveInfo(sendIntent,
+                () -> activity.getAdapter().addServiceResults(
+                        activity.createTestDisplayResolveInfo(sendIntent,
                                 ri,
                                 "testLabel",
                                 "testInfo",
@@ -858,29 +873,89 @@
         // TODO: restructure the tests b/129870719
         Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
 
-        assertThat("Chooser should have 3 targets (2apps, 1 direct)",
-                activity2.getAdapter().getCount(), is(3));
+        assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
+                activity.getAdapter().getCount(), is(3));
         assertThat("Chooser should have exactly one selectable direct target",
-                activity2.getAdapter().getSelectableServiceTargetCount(), is(1));
+                activity.getAdapter().getSelectableServiceTargetCount(), is(1));
         assertThat("The resolver info must match the resolver info used to create the target",
-                activity2.getAdapter().getItem(0).getResolveInfo(), is(ri));
+                activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
 
         // Click on the direct target
+        String name = serviceTargets.get(0).getTitle().toString();
         onView(withText(name))
                 .perform(click());
         waitForIdle();
 
-        // Currently we're seeing 6 invocations (3 from above, doubled up)
-        //      4. ChooserActivity.onCreate()
-        //      5. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
-        //      6. ChooserActivity.startSelected -- which is the one we're after
-        verify(mockLogger, Mockito.times(6)).write(logMakerCaptor.capture());
-        assertThat(logMakerCaptor.getAllValues().get(5).getCategory(),
+        // Currently we're seeing 3 invocations
+        //      1. ChooserActivity.onCreate()
+        //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
+        //      3. ChooserActivity.startSelected -- which is the one we're after
+        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
                 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
-        String hashedName2 = (String) logMakerCaptor
-                .getAllValues().get(5).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
-        assertThat("Hashing the same name should result in the same hashed value",
-                hashedName2, is(hashedName));
+        assertThat("The packages should match for app target and direct target", logMakerCaptor
+                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
+    }
+
+    // This test is too long and too slow and should not be taken as an example for future tests.
+    @Test
+    public void testDirectTargetLoggingWithAppTargetNotRanked() throws InterruptedException {
+        Intent sendIntent = createSendTextIntent();
+        // We need app targets for direct targets to get displayed
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15);
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+        // Set up resources
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        // Create direct share target
+        List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
+                resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName);
+        ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0);
+
+        // Start activity
+        final ChooserWrapperActivity activity = mActivityRule
+                .launchActivity(Intent.createChooser(sendIntent, null));
+        // Insert the direct share target
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                () -> activity.getAdapter().addServiceResults(
+                        activity.createTestDisplayResolveInfo(sendIntent,
+                                ri,
+                                "testLabel",
+                                "testInfo",
+                                sendIntent),
+                        serviceTargets,
+                        false)
+        );
+        // Thread.sleep shouldn't be a thing in an integration test but it's
+        // necessary here because of the way the code is structured
+        // TODO: restructure the tests b/129870719
+        Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
+
+        assertThat("Chooser should have 20 targets (4 apps, 1 direct, 15 A-Z)",
+                activity.getAdapter().getCount(), is(20));
+        assertThat("Chooser should have exactly one selectable direct target",
+                activity.getAdapter().getSelectableServiceTargetCount(), is(1));
+        assertThat("The resolver info must match the resolver info used to create the target",
+                activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
+
+        // Click on the direct target
+        String name = serviceTargets.get(0).getTitle().toString();
+        onView(withText(name))
+                .perform(click());
+        waitForIdle();
+
+        // Currently we're seeing 3 invocations
+        //      1. ChooserActivity.onCreate()
+        //      2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
+        //      3. ChooserActivity.startSelected -- which is the one we're after
+        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
+                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
+        assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
+                .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
     }
 
     private Intent createSendTextIntent() {
@@ -946,12 +1021,17 @@
         return infoList;
     }
 
-    private List<ChooserTarget> createDirectShareTargets(int numberOfResults) {
+    private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) {
         Icon icon = Icon.createWithBitmap(createBitmap());
         String testTitle = "testTitle";
         List<ChooserTarget> targets = new ArrayList<>();
         for (int i = 0; i < numberOfResults; i++) {
-            ComponentName componentName = ResolverDataProvider.createComponentName(i);
+            ComponentName componentName;
+            if (packageName.isEmpty()) {
+                componentName = ResolverDataProvider.createComponentName(i);
+            } else {
+                componentName = new ComponentName(packageName, packageName + ".class");
+            }
             ChooserTarget tempTarget = new ChooserTarget(
                     testTitle + i,
                     icon,
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index fb5c16b..e19ac81 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -37,7 +37,8 @@
     /**
      * When set to "true" the notification will be a generic confirm message instead of asking the
      * user if they want to turn on battery saver. If set to false the dialog will specifically
-     * talk about turning on battery saver and provide a button for taking the action.
+     * talk about battery saver without giving the option of turning it on. The only button visible
+     * will be a generic confirmation button to acknowledge the dialog.
      */
     public static final String EXTRA_CONFIRM_TEXT_ONLY = "extra_confirm_only";
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
new file mode 100644
index 0000000..ae8e1e2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.fuelgauge
+
+import android.content.Context
+import android.provider.Settings
+import java.time.Duration
+import java.time.Instant
+
+const val AVERAGE_TIME_TO_DISCHARGE_UNKNOWN = -1
+const val ESTIMATE_MILLIS_UNKNOWN = -1
+
+class Estimate(
+    val estimateMillis: Long,
+    val isBasedOnUsage: Boolean,
+    val averageDischargeTime: Long
+) {
+    companion object {
+        /**
+         * Returns the cached estimate if it is available and fresh. Will return null if estimate is
+         * unavailable or older than 2 minutes.
+         *
+         * @param context A valid context
+         * @return An [Estimate] object with the latest battery estimates.
+         */
+        @JvmStatic
+        fun getCachedEstimateIfAvailable(context: Context): Estimate? {
+            // if time > 2 min return null or the estimate otherwise
+            val resolver = context.contentResolver
+            val lastUpdateTime = Instant.ofEpochMilli(
+                    Settings.Global.getLong(
+                            resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, -1))
+            return if (Duration.between(lastUpdateTime,
+                            Instant.now()).compareTo(Duration.ofMinutes(2)) > 0) {
+                null
+            } else Estimate(
+                    Settings.Global.getLong(resolver,
+                            Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS,
+                            ESTIMATE_MILLIS_UNKNOWN.toLong()),
+                    Settings.Global.getInt(resolver,
+                            Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE, 0) == 1,
+                    Settings.Global.getLong(resolver, Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
+                            AVERAGE_TIME_TO_DISCHARGE_UNKNOWN.toLong()))
+        }
+
+        /**
+         * Stores an estimate to the cache along with a timestamp. Can be obtained via
+         * [.getCachedEstimateIfAvailable].
+         *
+         * @param context A valid context
+         * @param estimate the [Estimate] object to store
+         */
+        @JvmStatic
+        fun storeCachedEstimate(context: Context, estimate: Estimate) {
+            // store the estimate and update the timestamp
+            val resolver = context.contentResolver
+            Settings.Global.putLong(resolver, Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS,
+                    estimate.estimateMillis)
+            Settings.Global.putInt(resolver, Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE,
+                    if (estimate.isBasedOnUsage) 1 else 0)
+            Settings.Global.putLong(resolver, Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
+                    estimate.averageDischargeTime)
+            Settings.Global.putLong(resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
+                    System.currentTimeMillis())
+        }
+    }
+}
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 49c16be..dce9ce1 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -21,8 +21,6 @@
     android:id="@+id/privacy_chip"
     android:layout_height="match_parent"
     android:layout_width="wrap_content"
-    android:layout_marginLeft="@dimen/ongoing_appops_chip_margin"
-    android:layout_marginRight="@dimen/ongoing_appops_chip_margin"
     android:layout_gravity="center_vertical|end"
     android:gravity="center_vertical"
     android:orientation="horizontal"
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index b94a316..8f74806 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -19,6 +19,7 @@
     android:id="@+id/linear_carrier"
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
+    android:minWidth="48dp"
     android:orientation="horizontal"
     android:gravity="center_vertical|start"
     android:background="@android:color/transparent"
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index e44fbcf..8878786 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -18,7 +18,7 @@
 <com.android.systemui.qs.PagedTileLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
+    android:layout_height="0dp"
     android:layout_weight="1"
     android:clipChildren="true"
     android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 29f53a4..79e2dfb 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -21,8 +21,8 @@
     android:layout_height="wrap_content"
     android:layout_marginTop="@dimen/qs_header_top_margin"
     android:layout_marginBottom="14dp"
-    android:layout_marginStart="@dimen/status_bar_padding_start"
-    android:layout_marginEnd="@dimen/status_bar_padding_end"
+    android:paddingStart="@dimen/status_bar_padding_start"
+    android:paddingEnd="@dimen/status_bar_padding_end"
     android:layout_below="@id/quick_status_bar_system_icons"
     android:clipChildren="false"
     android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index da640fd..37c6d9f 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -19,7 +19,6 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/qs_header_tooltip_height"
     android:layout_below="@id/quick_status_bar_system_icons"
-    android:layout_marginTop="@dimen/qs_header_top_margin"
     android:paddingStart="@dimen/status_bar_padding_start"
     android:paddingEnd="@dimen/status_bar_padding_end">
 
@@ -27,7 +26,7 @@
         android:id="@+id/long_press_tooltip"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="start|bottom"
+        android:layout_gravity="start|center_vertical"
         android:alpha="0"
         android:text="@string/quick_settings_header_onboarding_text"
         android:textAppearance="@style/TextAppearance.QS.TileLabel"
@@ -36,34 +35,48 @@
 
     <LinearLayout
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="start|bottom"
+        android:layout_height="match_parent"
+        android:layout_gravity="start|center_vertical"
         android:gravity="center_vertical">
 
         <LinearLayout
             android:id="@+id/status_container"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="match_parent"
             android:layout_gravity="start|center_vertical"
             android:layout_weight="1"
             android:gravity="center_vertical"
-            android:alpha="0">
+            android:alpha="0" >
 
-            <ImageView
-                android:id="@+id/next_alarm_icon"
-                android:layout_width="@dimen/qs_header_alarm_icon_size"
-                android:layout_height="@dimen/qs_header_alarm_icon_size"
-                android:src="@drawable/stat_sys_alarm"
-                android:tint="?android:attr/textColorPrimary"
-                android:visibility="gone"/>
-
-            <TextView
-                android:id="@+id/next_alarm_text"
+            <LinearLayout
+                android:id = "@+id/alarm_container"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
-                android:textAppearance="@style/TextAppearance.QS.Status"
-                android:visibility="gone"/>
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:gravity="center_vertical"
+                android:focusable="true"
+                android:clickable="true">
+
+                <ImageView
+                    android:id="@+id/next_alarm_icon"
+                    android:layout_width="@dimen/qs_header_alarm_icon_size"
+                    android:layout_height="@dimen/qs_header_alarm_icon_size"
+                    android:src="@drawable/ic_alarm"
+                    android:tint="?android:attr/textColorPrimary"
+                    android:contentDescription="@string/accessibility_quick_settings_alarm_set"
+                    android:visibility="gone"/>
+
+                <TextView
+                    android:id="@+id/next_alarm_text"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:ellipsize="marquee"
+                    android:marqueeRepeatLimit="marquee_forever"
+                    android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
+                    android:textAppearance="@style/TextAppearance.QS.Status"
+                    android:visibility="gone"/>
+            </LinearLayout>
 
             <View
                 android:id="@+id/status_separator"
@@ -71,20 +84,33 @@
                 android:layout_height="match_parent"
                 android:visibility="gone"/>
 
-            <ImageView
-                android:id="@+id/ringer_mode_icon"
-                android:layout_width="@dimen/qs_header_alarm_icon_size"
-                android:layout_height="@dimen/qs_header_alarm_icon_size"
-                android:tint="?android:attr/textColorPrimary"
-                android:visibility="gone"/>
-
-            <TextView
-                android:id="@+id/ringer_mode_text"
+            <LinearLayout
+                android:id = "@+id/ringer_container"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
-                android:textAppearance="@style/TextAppearance.QS.Status"
-                android:visibility="gone"/>
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:gravity="center_vertical"
+                android:focusable="true"
+                android:clickable="true">
+
+                <ImageView
+                    android:id="@+id/ringer_mode_icon"
+                    android:layout_width="@dimen/qs_header_alarm_icon_size"
+                    android:layout_height="@dimen/qs_header_alarm_icon_size"
+                    android:tint="?android:attr/textColorPrimary"
+                    android:visibility="gone"/>
+
+                <TextView
+                    android:id="@+id/ringer_mode_text"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:ellipsize="marquee"
+                    android:marqueeRepeatLimit="marquee_forever"
+                    android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
+                    android:textAppearance="@style/TextAppearance.QS.Status"
+                    android:visibility="gone"/>
+            </LinearLayout>
         </LinearLayout>
 
         <View
@@ -93,11 +119,13 @@
             android:layout_height="match_parent"
             android:layout_weight="1"/>
 
+
         <include layout="@layout/qs_carrier_group"
                  android:id="@+id/carrier_group"
                  android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android_layout_gravity="center vertical|end"/>
+                 android:layout_height="match_parent"
+                 android:layout_gravity="end|center_vertical"
+                 android:focusable="false"/>
     </LinearLayout>
 
 </FrameLayout>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index e768939..90e78e8 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,8 +24,8 @@
 
     <dimen name="brightness_mirror_height">40dp</dimen>
 
-    <dimen name="qs_tile_margin_top">2dp</dimen>
-    <dimen name="qs_header_tooltip_height">24dp</dimen>
+    <dimen name="qs_tile_margin_top">8dp</dimen>
+    <dimen name="qs_tile_margin_vertical">0dp</dimen>
 
     <dimen name="battery_detail_graph_space_top">9dp</dimen>
     <dimen name="battery_detail_graph_space_bottom">9dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5d8b9e6..7d76160 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -437,7 +437,7 @@
     <dimen name="qs_tile_padding_bottom">16dp</dimen>
     <dimen name="qs_tile_spacing">4dp</dimen>
     <dimen name="qs_panel_padding_bottom">0dp</dimen>
-    <dimen name="qs_panel_padding_top">30dp</dimen>
+    <dimen name="qs_panel_padding_top">@dimen/qs_header_tooltip_height</dimen>
     <dimen name="qs_detail_header_height">56dp</dimen>
     <dimen name="qs_detail_header_padding">0dp</dimen>
     <dimen name="qs_detail_image_width">56dp</dimen>
@@ -461,8 +461,8 @@
     <dimen name="qs_detail_item_icon_width">32dp</dimen>
     <dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
     <dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
-    <dimen name="qs_header_tooltip_height">18dp</dimen>
-    <dimen name="qs_header_alarm_icon_size">18dp</dimen>
+    <dimen name="qs_header_tooltip_height">48dp</dimen>
+    <dimen name="qs_header_alarm_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
     <dimen name="qs_header_mobile_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
     <dimen name="qs_header_alarm_text_margin_start">6dp</dimen>
     <dimen name="qs_header_separator_width">8dp</dimen>
@@ -473,7 +473,7 @@
     <dimen name="qs_footer_padding_end">16dp</dimen>
     <dimen name="qs_footer_icon_size">16dp</dimen>
     <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
-    <dimen name="qs_header_top_margin">12dp</dimen>
+    <dimen name="qs_header_top_margin">15dp</dimen>
 
     <dimen name="qs_notif_collapsed_space">64dp</dimen>
 
@@ -1031,8 +1031,6 @@
     <dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
     <!-- Text size for Ongoing App Ops dialog items -->
     <dimen name="ongoing_appops_dialog_item_size">16sp</dimen>
-    <!-- Side margins around the Ongoing App Ops chip-->
-    <dimen name="ongoing_appops_chip_margin">0dp</dimen>
     <!-- Height of the Ongoing App Ops chip -->
     <dimen name="ongoing_appops_chip_height">32dp</dimen>
     <!-- Padding between background of Ongoing App Ops chip and content -->
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index eca3926..2e9b03c 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -383,7 +383,7 @@
         }
 
         if (TextUtils.isEmpty(displayText) && !airplaneMode) {
-            displayText = TextUtils.join(mSeparator, carrierNames);
+            displayText = joinNotEmpty(mSeparator, carrierNames);
         }
         final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
                 displayText,
@@ -546,6 +546,25 @@
         }
     }
 
+    /**
+     * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra
+     * separator added so there are no extra separators that are not needed.
+     */
+    private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) {
+        int length = sequences.length;
+        if (length == 0) return "";
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < length; i++) {
+            if (!TextUtils.isEmpty(sequences[i])) {
+                if (!TextUtils.isEmpty(sb)) {
+                    sb.append(separator);
+                }
+                sb.append(sequences[i]);
+            }
+        }
+        return sb.toString();
+    }
+
     private static List<CharSequence> append(List<CharSequence> list, CharSequence string) {
         if (!TextUtils.isEmpty(string)) {
             list.add(string);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 94bb1f3..1bd8e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -204,6 +204,11 @@
         return false;
     }
 
+    /** Called when the user is performing an assistant invocation action (e.g. Active Edge) */
+    public void onInvocationProgress(int type, float progress) {
+        // intentional no-op, vendor's AssistManager implementation should override if needed.
+    }
+
     public void hideAssist() {
         mAssistUtils.hideCurrentSession();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 9d9c88f..744f88d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -86,7 +86,7 @@
 
     @Retention(SOURCE)
     @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
-            DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION})
+            DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE})
     @interface DismissReason {}
 
     static final int DISMISS_USER_GESTURE = 1;
@@ -95,6 +95,7 @@
     static final int DISMISS_BLOCKED = 4;
     static final int DISMISS_NOTIF_CANCEL = 5;
     static final int DISMISS_ACCESSIBILITY_ACTION = 6;
+    static final int DISMISS_NO_LONGER_BUBBLE = 7;
 
     static final int MAX_BUBBLES = 5; // TODO: actually enforce this
 
@@ -129,8 +130,7 @@
     private final StatusBarWindowController mStatusBarWindowController;
     private StatusBarStateListener mStatusBarStateListener;
 
-    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
-            Dependency.get(NotificationInterruptionStateProvider.class);
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
 
     private INotificationManager mNotificationManagerService;
 
@@ -189,15 +189,19 @@
 
     @Inject
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-            BubbleData data, ConfigurationController configurationController) {
+            BubbleData data, ConfigurationController configurationController,
+            NotificationInterruptionStateProvider interruptionStateProvider) {
         this(context, statusBarWindowController, data, null /* synchronizer */,
-                configurationController);
+                configurationController, interruptionStateProvider);
     }
 
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
             BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            NotificationInterruptionStateProvider interruptionStateProvider) {
         mContext = context;
+        mNotificationInterruptionStateProvider = interruptionStateProvider;
+
         configurationController.addCallback(this /* configurationListener */);
 
         mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
@@ -394,7 +398,7 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (shouldAutoBubbleForFlags(mContext, entry) || shouldBubble(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
                 // TODO: handle group summaries?
                 updateShowInShadeForSuppressNotification(entry);
             }
@@ -405,7 +409,7 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (entry.isBubble() && mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
                 updateBubble(entry);
             }
         }
@@ -415,8 +419,11 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
-                    && alertAgain(entry, entry.notification.getNotification())) {
+            boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry);
+            if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.key)) {
+                // It was previously a bubble but no longer a bubble -- lets remove it
+                removeBubble(entry.key, DISMISS_NO_LONGER_BUBBLE);
+            } else if (shouldBubble && alertAgain(entry, entry.notification.getNotification())) {
                 updateShowInShadeForSuppressNotification(entry);
                 entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
                 updateBubble(entry);
@@ -561,17 +568,6 @@
     }
 
     /**
-     * Whether the notification has been developer configured to bubble and is allowed by the user.
-     */
-    @VisibleForTesting
-    protected boolean shouldBubble(NotificationEntry entry) {
-        StatusBarNotification n = entry.notification;
-        boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null
-                && n.getNotification().getBubbleMetadata().getIntent() != null;
-        return hasOverlayIntent && entry.canBubble;
-    }
-
-    /**
      * Whether the notification should automatically bubble or not. Gated by secure settings flags.
      */
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index e7878c6..669348e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -117,6 +117,7 @@
             } else {
                 parent.addView(v);
             }
+            parent.setVisibility(View.VISIBLE);
         }
         updateSnapPosition();
         updateSeparatedButtonSize();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 9c71ffc..6bc975a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -41,6 +41,21 @@
     private static final String TAG = "ListGridLayout";
     private int mExpectedCount;
 
+    // number of rows and columns to use for different numbers of items
+    private final int[][] mConfigs = {
+            // {rows, columns}
+            {0, 0}, // 0 items
+            {1, 1}, // 1 item
+            {1, 2}, // 2 items
+            {1, 3}, // 3 items
+            {2, 2}, // 4 items
+            {2, 3}, // 5 items
+            {2, 3}, // 6 items
+            {3, 3}, // 7 items
+            {3, 3}, // 8 items
+            {3, 3}  // 9 items
+    };
+
     public ListGridLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -53,19 +68,28 @@
             ViewGroup subList = (ViewGroup) getChildAt(i);
             if (subList != null) {
                 subList.removeAllViews();
+                subList.setVisibility(View.GONE);
             }
         }
     }
 
     /**
      * Get the parent view associated with the item which should be placed at the given position.
+     * @param index The index of the item.
+     * @param reverseSublists Reverse the order of sublists. Ordinarily, sublists fill from first to
+     *                        last, whereas setting this to true will fill them last to first.
+     * @param swapRowsAndColumns Swap the order in which rows and columns are filled. By default,
+     *                           columns fill first, adding one item to each row. Setting this to
+     *                           true will cause rows to fill first, adding one item to each column.
+     * @return
      */
     public ViewGroup getParentView(int index, boolean reverseSublists, boolean swapRowsAndColumns) {
-        if (getRowCount() == 0) {
+        if (getRowCount() == 0 || index < 0) {
             return null;
         }
-        int column = getParentViewIndex(index, reverseSublists, swapRowsAndColumns);
-        return (ViewGroup) getChildAt(column);
+        int targetIndex = Math.min(index, getMaxElementCount() - 1);
+        int row = getParentViewIndex(targetIndex, reverseSublists, swapRowsAndColumns);
+        return (ViewGroup) getChildAt(row);
     }
 
     private int reverseSublistIndex(int index) {
@@ -74,7 +98,6 @@
 
     private int getParentViewIndex(int index, boolean reverseSublists, boolean swapRowsAndColumns) {
         int sublistIndex;
-        ViewGroup row;
         int rows = getRowCount();
         if (swapRowsAndColumns) {
             sublistIndex = (int) Math.floor(index / rows);
@@ -92,42 +115,31 @@
      */
     public void setExpectedCount(int count) {
         mExpectedCount = count;
-
-        for (int i = 0; i < getChildCount(); i++) {
-            if (i <= getColumnCount()) {
-                setSublistVisibility(i, true);
-            } else {
-                setSublistVisibility(i, false);
-            }
-        }
     }
 
-    private void setSublistVisibility(int index, boolean visible) {
-        View subList = getChildAt(index);
-        if (subList != null) {
-            subList.setVisibility(visible ? View.VISIBLE : View.GONE);
+    private int getMaxElementCount() {
+        return mConfigs.length - 1;
+    }
+
+    private int[] getConfig() {
+        if (mExpectedCount < 0) {
+            return mConfigs[0];
         }
+        int targetElements = Math.min(getMaxElementCount(), mExpectedCount);
+        return mConfigs[targetElements];
     }
 
     /**
      * Get the number of rows which will be used to render children.
      */
     public int getRowCount() {
-        // special case for 3 to use a single row
-        if (mExpectedCount == 3) {
-            return 1;
-        }
-        return (int) Math.round(Math.sqrt(mExpectedCount));
+        return getConfig()[0];
     }
 
     /**
      * Get the number of columns which will be used to render children.
      */
     public int getColumnCount() {
-        // special case for 3 to use a single row
-        if (mExpectedCount == 3) {
-            return 3;
-        }
-        return (int) Math.ceil(Math.sqrt(mExpectedCount));
+        return getConfig()[1];
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6af7ac4..d363622 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -66,8 +66,6 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
@@ -362,7 +360,6 @@
 
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
-    private boolean mLockWhenSimRemoved;
     private CharSequence mCustomMessage;
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -465,7 +462,6 @@
                         if (simState == ABSENT) {
                             // MVNO SIMs can become transiently NOT_READY when switching networks,
                             // so we should only lock when they are ABSENT.
-                            onSimAbsentLocked();
                             if (simWasLocked) {
                                 if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
                                         + "previous state was locked. Reset the state.");
@@ -498,7 +494,6 @@
                                   + "show permanently disabled message in lockscreen.");
                             resetStateLocked();
                         }
-                        onSimAbsentLocked();
                     }
                     break;
                 case READY:
@@ -509,7 +504,6 @@
                                     + "previous state was locked. Reset the state.");
                             resetStateLocked();
                         }
-                        mLockWhenSimRemoved = true;
                     }
                     break;
                 default:
@@ -518,18 +512,6 @@
             }
         }
 
-        private void onSimAbsentLocked() {
-            if (isSecure() && mLockWhenSimRemoved && !mShuttingDown) {
-                mLockWhenSimRemoved = false;
-                MetricsLogger.action(mContext,
-                        MetricsProto.MetricsEvent.ACTION_LOCK_BECAUSE_SIM_REMOVED, mShowing);
-                if (!mShowing) {
-                    Log.i(TAG, "SIM removed, showing keyguard");
-                    doKeyguardLocked(null);
-                }
-            }
-        }
-
         @Override
         public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
             final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
index 02ad0f1..f73bc93 100644
--- a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
@@ -15,6 +15,7 @@
     val severeLevelThreshold: Int,
     val lowLevelThreshold: Int,
     val timeRemainingMillis: Long,
+    val averageTimeToDischargeMillis: Long,
     val severeThresholdMillis: Long,
     val lowThresholdMillis: Long,
     val isBasedOnUsage: Boolean,
@@ -39,18 +40,19 @@
         severeLevelThreshold: Int,
         lowLevelThreshold: Int
     ) : this(
-        batteryLevel,
-        isPowerSaver,
-        plugged,
-        bucket,
-        batteryStatus,
-        severeLevelThreshold,
-        lowLevelThreshold,
-        NO_ESTIMATE_AVAILABLE.toLong(),
-        NO_ESTIMATE_AVAILABLE.toLong(),
-        NO_ESTIMATE_AVAILABLE.toLong(),
-        false,
-        true
+            batteryLevel,
+            isPowerSaver,
+            plugged,
+            bucket,
+            batteryStatus,
+            severeLevelThreshold,
+            lowLevelThreshold,
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            false,
+            true
     ) {
         this.isHybrid = false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
index a879227..3b46478 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
@@ -1,5 +1,7 @@
 package com.android.systemui.power;
 
+import com.android.settingslib.fuelgauge.Estimate;
+
 public interface EnhancedEstimates {
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
index bfb809e..9b1f23a 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
@@ -1,5 +1,7 @@
 package com.android.systemui.power;
 
+import com.android.settingslib.fuelgauge.Estimate;
+
 public class EnhancedEstimatesImpl implements EnhancedEstimates {
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt b/packages/SystemUI/src/com/android/systemui/power/Estimate.kt
deleted file mode 100644
index dca0d45..0000000
--- a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.android.systemui.power
-
-data class Estimate(val estimateMillis: Long, val isBasedOnUsage: Boolean)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 25d6d94..b57c053 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -42,6 +42,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -283,6 +284,7 @@
             mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode,
                     plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
                     mLowBatteryReminderLevels[0], estimate.getEstimateMillis(),
+                    estimate.getAverageDischargeTime(),
                     mEnhancedEstimates.getSevereWarningThreshold(),
                     mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(),
                     mEnhancedEstimates.getLowWarningEnabled());
@@ -316,7 +318,8 @@
             return estimate;
         }
         return new Estimate(mLastBatteryStateSnapshot.getTimeRemainingMillis(),
-                mLastBatteryStateSnapshot.isBasedOnUsage());
+                mLastBatteryStateSnapshot.isBasedOnUsage(),
+                mLastBatteryStateSnapshot.getAverageTimeToDischargeMillis());
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ebc3a6a..e22a21a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -63,6 +63,7 @@
     private int mLayoutDirection;
     private int mHorizontalClipBound;
     private final Rect mClippingRect;
+    private int mLastMaxHeight = -1;
 
     public PagedTileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -303,8 +304,11 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 
         final int nTiles = mTiles.size();
-        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+        // If we have no reason to recalculate the number of rows, skip this step. In particular,
+        // if the height passed by its parent is the same as the last time, we try not to remeasure.
+        if (mDistributeTiles || mLastMaxHeight != MeasureSpec.getSize(heightMeasureSpec)) {
 
+            mLastMaxHeight = MeasureSpec.getSize(heightMeasureSpec);
             // Only change the pages if the number of rows or columns (from updateResources) has
             // changed or the tiles have changed
             if (mPages.get(0).updateMaxRows(heightMeasureSpec, nTiles) || mDistributeTiles) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index 7de8b74..e352b58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -19,6 +19,8 @@
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
 import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -30,6 +32,7 @@
 import com.android.keyguard.CarrierTextController;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.NetworkController;
 
 import javax.inject.Inject;
@@ -40,7 +43,7 @@
  */
 public class QSCarrierGroup extends LinearLayout implements
         CarrierTextController.CarrierTextCallback,
-        NetworkController.SignalCallback {
+        NetworkController.SignalCallback, View.OnClickListener {
 
     private static final String TAG = "QSCarrierGroup";
     /**
@@ -53,20 +56,29 @@
     private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
     private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
     private CarrierTextController mCarrierTextController;
+    private ActivityStarter mActivityStarter;
 
     private boolean mListening;
 
     @Inject
     public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
-            NetworkController networkController) {
+            NetworkController networkController, ActivityStarter activityStarter) {
         super(context, attrs);
         mNetworkController = networkController;
+        mActivityStarter = activityStarter;
     }
 
     @VisibleForTesting
     public QSCarrierGroup(Context context, AttributeSet attrs) {
         this(context, attrs,
-                Dependency.get(NetworkController.class));
+                Dependency.get(NetworkController.class),
+                Dependency.get(ActivityStarter.class));
+    }
+
+    @Override
+    public void onClick(View v) {
+        mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+                Settings.ACTION_WIRELESS_SETTINGS), 0);
     }
 
     @Override
@@ -82,6 +94,7 @@
 
         for (int i = 0; i < SIM_SLOTS; i++) {
             mInfos[i] = new CellSignalState();
+            mCarrierGroups[i].setOnClickListener(this);
         }
 
         CharSequence separator = mContext.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index dbd3042..f0413cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -103,7 +103,9 @@
         if (navBelow) {
             maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
         }
-        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
+        // Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
+        // measured last, after other views and padding is accounted for.
+        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
         int width = mQSPanel.getMeasuredWidth();
         int height = layoutParams.topMargin + layoutParams.bottomMargin
                 + mQSPanel.getMeasuredHeight() + getPaddingBottom();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index d6e0306..fcaf981 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -128,6 +128,24 @@
         addView(mDivider);
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // We want all the logic of LinearLayout#onMeasure, and for it to assign the excess space
+        // not used by the other children to PagedTileLayout. However, in this case, LinearLayout
+        // assumes that PagedTileLayout would use all the excess space. This is not the case as
+        // PagedTileLayout height is quantized (because it shows a certain number of rows).
+        // Therefore, after everything is measured, we need to make sure that we add up the correct
+        // total height
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int height = getPaddingBottom() + getPaddingTop();
+        int numChildren = getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE) height += child.getMeasuredHeight();
+        }
+        setMeasuredDimension(getMeasuredWidth(), height);
+    }
+
     public View getDivider() {
         return mDivider;
     }
@@ -282,6 +300,7 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mFooter.onConfigurationChanged();
+        updateResources();
 
         updateBrightnessMirror();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index d789821..2e3065a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -35,6 +35,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.AlarmClock;
+import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
@@ -133,9 +134,11 @@
     private ImageView mNextAlarmIcon;
     /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
     private TextView mNextAlarmTextView;
+    private View mNextAlarmContainer;
     private View mStatusSeparator;
     private ImageView mRingerModeIcon;
     private TextView mRingerModeTextView;
+    private View mRingerContainer;
     private Clock mClockView;
     private DateView mDateView;
     private OngoingPrivacyChip mPrivacyChip;
@@ -203,10 +206,14 @@
         mStatusSeparator = findViewById(R.id.status_separator);
         mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
         mNextAlarmTextView = findViewById(R.id.next_alarm_text);
+        mNextAlarmContainer = findViewById(R.id.alarm_container);
+        mNextAlarmContainer.setOnClickListener(this::onClick);
         mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
         mRingerModeTextView = findViewById(R.id.ringer_mode_text);
+        mRingerContainer = findViewById(R.id.ringer_container);
+        mRingerContainer.setOnClickListener(this::onClick);
         mPrivacyChip = findViewById(R.id.privacy_chip);
-        mPrivacyChip.setOnClickListener(this);
+        mPrivacyChip.setOnClickListener(this::onClick);
         mCarrierGroup = findViewById(R.id.carrier_group);
 
 
@@ -236,6 +243,8 @@
         // QS will always show the estimate, and BatteryMeterView handles the case where
         // it's unavailable or charging
         mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
+        mRingerModeTextView.setSelected(true);
+        mNextAlarmTextView.setSelected(true);
     }
 
     private List<String> getIgnoredIconSlots() {
@@ -285,11 +294,11 @@
         if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
                 mZenController.getConsolidatedPolicy())) {
             if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
-                mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
+                mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
                 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
                 ringerVisible = true;
             } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
-                mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
+                mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
                 mRingerModeTextView.setText(R.string.qs_status_phone_muted);
                 ringerVisible = true;
             }
@@ -546,7 +555,7 @@
 
     @Override
     public void onClick(View v) {
-        if (v == mClockView) {
+        if (v == mClockView || v == mNextAlarmContainer) {
             mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
                     AlarmClock.ACTION_SHOW_ALARMS),0);
         } else if (v == mPrivacyChip) {
@@ -561,6 +570,9 @@
                         new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
                 mHost.collapsePanels();
             });
+        } else if (v == mRingerContainer) {
+            mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+                    Settings.ACTION_SOUND_SETTINGS), 0);
         }
     }
 
@@ -573,7 +585,6 @@
     @Override
     public void onZenChanged(int zen) {
         updateStatusText();
-
     }
 
     @Override
@@ -731,8 +742,10 @@
     public void setMargins(int sideMargins) {
         for (int i = 0; i < getChildCount(); i++) {
             View v = getChildAt(i);
+            // Prevents these views from getting set a margin.
+            // The Icon views all have the same padding set in XML to be aligned.
             if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel
-                    || v == mPrivacyChip) {
+                    || v == mHeaderTextContainerView) {
                 continue;
             }
             RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 1dd729d..8aacd72 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -137,7 +137,8 @@
      * @param tilesCount Upper limit on the number of tiles to show. to prevent empty rows.
      */
     public boolean updateMaxRows(int heightMeasureSpec, int tilesCount) {
-        final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop;
+        final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop
+                + mCellMarginVertical;
         final int previousRows = mRows;
         mRows = availableHeight / (mCellHeight + mCellMarginVertical);
         if (mRows >= mMaxAllowedRows) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 8d2f895..f26a94f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -81,6 +81,7 @@
         state.icon = mIcon;
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.showRippleEffect = false;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 2f99cf3..d584959 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,10 @@
 
 import static android.app.StatusBarManager.DISABLE2_NONE;
 import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
 
@@ -40,6 +43,7 @@
 import android.os.Message;
 import android.util.Pair;
 import android.util.SparseArray;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -127,6 +131,11 @@
     private Handler mHandler = new H(Looper.getMainLooper());
     /** A map of display id - disable flag pair */
     private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>();
+    /**
+     * The last ID of the display where IME window for which we received setImeWindowStatus
+     * event.
+     */
+    private int mLastUpdatedImeDisplayId = INVALID_DISPLAY;
 
     /**
      * These methods are called back on the main thread.
@@ -785,6 +794,32 @@
         }
     }
 
+    private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher) {
+        if (displayId == INVALID_DISPLAY) return;
+
+        if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED
+                && mLastUpdatedImeDisplayId != displayId
+                && mLastUpdatedImeDisplayId != INVALID_DISPLAY) {
+            // Set previous NavBar's IME window status as invisible when IME
+            // window switched to another display for single-session IME case.
+            sendImeInvisibleStatusForPrevNavBar();
+        }
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).setImeWindowStatus(displayId, token, vis, backDisposition,
+                    showImeSwitcher);
+        }
+        mLastUpdatedImeDisplayId = displayId;
+    }
+
+    private void sendImeInvisibleStatusForPrevNavBar() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId,
+                    null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT,
+                    false /* showImeSwitcher */);
+        }
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -852,10 +887,9 @@
                     break;
                 case MSG_SHOW_IME_BUTTON:
                     args = (SomeArgs) msg.obj;
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).setImeWindowStatus(args.argi1, (IBinder) args.arg1,
-                                args.argi2, args.argi3, args.argi4 != 0 /* showImeSwitcher */);
-                    }
+                    handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */,
+                            args.argi2 /* vis */, args.argi3 /* backDisposition */,
+                            args.argi4 != 0 /* showImeSwitcher */);
                     break;
                 case MSG_SHOW_RECENT_APPS:
                     for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 2da6824..6adaa0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -149,6 +149,13 @@
         updateIconColor();
     }
 
+    /**
+     * If current drawable should be tinted.
+     */
+    public boolean shouldTint() {
+        return mShouldTint;
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -168,6 +175,9 @@
     }
 
     public void setPreviewView(View v) {
+        if (mPreviewView == v) {
+            return;
+        }
         View oldPreviewView = mPreviewView;
         mPreviewView = v;
         if (mPreviewView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 059c3f6..926d4b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -147,7 +147,14 @@
      * @return true if the entry should bubble up, false otherwise
      */
     public boolean shouldBubbleUp(NotificationEntry entry) {
-        StatusBarNotification sbn = entry.notification;
+        final StatusBarNotification sbn = entry.notification;
+        if (!entry.canBubble) {
+            if (DEBUG) {
+                Log.d(TAG, "No bubble up: not allowed to bubble: " + sbn.getKey());
+            }
+            return false;
+        }
+
         if (!entry.isBubble()) {
             if (DEBUG) {
                 Log.d(TAG, "No bubble up: notification " + sbn.getKey()
@@ -156,6 +163,15 @@
             return false;
         }
 
+        final Notification n = sbn.getNotification();
+        if (n.getBubbleMetadata() == null || n.getBubbleMetadata().getIntent() == null) {
+            if (DEBUG) {
+                Log.d(TAG, "No bubble up: notification: " + sbn.getKey()
+                        + " doesn't have valid metadata");
+            }
+            return false;
+        }
+
         if (!canHeadsUpCommon(entry)) {
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index cb64f10..5b464a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -337,7 +337,10 @@
     private void updateRightAffordanceIcon() {
         IconState state = mRightButton.getIcon();
         mRightAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE);
-        mRightAffordanceView.setImageDrawable(state.drawable, state.tint);
+        if (state.drawable != mRightAffordanceView.getDrawable()
+                || state.tint != mRightAffordanceView.shouldTint()) {
+            mRightAffordanceView.setImageDrawable(state.drawable, state.tint);
+        }
         mRightAffordanceView.setContentDescription(state.contentDescription);
     }
 
@@ -389,7 +392,10 @@
     private void updateLeftAffordanceIcon() {
         IconState state = mLeftButton.getIcon();
         mLeftAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE);
-        mLeftAffordanceView.setImageDrawable(state.drawable, state.tint);
+        if (state.drawable != mLeftAffordanceView.getDrawable()
+                || state.tint != mLeftAffordanceView.shouldTint()) {
+            mLeftAffordanceView.setImageDrawable(state.drawable, state.tint);
+        }
         mLeftAffordanceView.setContentDescription(state.contentDescription);
     }
 
@@ -715,11 +721,6 @@
         updateLeftPreview();
     }
 
-    public void onKeyguardShowingChanged() {
-        updateLeftAffordance();
-        inflateCameraPreview();
-    }
-
     private void setRightButton(IntentButton button) {
         mRightButton = button;
         updateRightAffordanceIcon();
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 4d2b56c..6c1a4fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1063,4 +1063,9 @@
         context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
         return navigationBarView;
     }
+
+    @VisibleForTesting
+    int getNavigationIconHints() {
+        return mNavigationIconHints;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 57b2ee9..2207e04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1304,7 +1304,6 @@
             mKeyguardStatusBar.setAlpha(1f);
             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
             if (keyguardShowing && oldState != mBarState) {
-                mKeyguardBottomArea.onKeyguardShowingChanged();
                 if (mQs != null) {
                     mQs.hideImmediately();
                 }
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 a381bbc..3f33ba6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3926,6 +3926,10 @@
                 mScrimController.setWakeLockScreenSensorActive(true);
             }
 
+            if (reason == DozeLog.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
+                mStatusBarWindow.suppressWakeUpGesture(true);
+            }
+
             boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION;
             // Set the state to pulsing, so ScrimController will know what to do once we ask it to
             // execute the transition. The pulse callback will then be invoked when the scrims
@@ -3945,6 +3949,9 @@
                     callback.onPulseFinished();
                     updateNotificationPanelTouchState();
                     mScrimController.setWakeLockScreenSensorActive(false);
+                    if (mStatusBarWindow != null) {
+                        mStatusBarWindow.suppressWakeUpGesture(false);
+                    }
                     setPulsing(false);
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 28db28c..44996ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -107,12 +107,13 @@
     private boolean mTouchActive;
     private boolean mExpandAnimationRunning;
     private boolean mExpandAnimationPending;
+    private boolean mSuppressingWakeUpGesture;
 
     private final GestureDetector.SimpleOnGestureListener mGestureListener =
             new GestureDetector.SimpleOnGestureListener() {
         @Override
         public boolean onSingleTapConfirmed(MotionEvent e) {
-            if (mSingleTapEnabled) {
+            if (mSingleTapEnabled && !mSuppressingWakeUpGesture) {
                 mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
                         "SINGLE_TAP");
                 return true;
@@ -327,6 +328,10 @@
         mTouchActive = touchActive;
     }
 
+    void suppressWakeUpGesture(boolean suppress) {
+        mSuppressingWakeUpGesture = suppress;
+    }
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 273fa55..fde1455 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -31,10 +31,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
+import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.power.EnhancedEstimates;
-import com.android.systemui.power.Estimate;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index df534d7..9f91a17 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -104,7 +104,8 @@
 
         mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("",
                 new CharSequence[]{}, false, new int[]{});
-        when(mTelephonyManager.getPhoneCount()).thenReturn(2);
+        when(mTelephonyManager.getPhoneCount()).thenReturn(3);
+
         mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true,
                 mKeyguardUpdateMonitor);
         // This should not start listening on any of the real dependencies
@@ -130,6 +131,12 @@
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
+                new ArrayList<>());
+
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 IccCardConstants.State.CARD_IO_ERROR);
         // This should not produce an out of bounds error, even though there are no subscriptions
@@ -173,7 +180,11 @@
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
         when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -197,7 +208,11 @@
         list.add(TEST_SUBSCRIPTION_ROAMING);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
         when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -219,6 +234,12 @@
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
+                new ArrayList<>());
+
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
                 ArgumentCaptor.forClass(
                         CarrierTextController.CarrierTextCallbackInfo.class);
@@ -233,6 +254,121 @@
 
     }
 
+    @Test
+    public void testCarrierText_twoValidSubscriptions() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mCarrierTextController.updateCarrierText();
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
+    public void testCarrierText_oneDisabledSub() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt()))
+                .thenReturn(IccCardConstants.State.READY)
+                .thenReturn(IccCardConstants.State.NOT_READY);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mCarrierTextController.updateCarrierText();
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
+    public void testCarrierText_firstDisabledSub() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt()))
+                .thenReturn(IccCardConstants.State.NOT_READY)
+                .thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mCarrierTextController.updateCarrierText();
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
+    @Test
+    public void testCarrierText_threeSubsMiddleDisabled() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt()))
+                .thenReturn(IccCardConstants.State.READY)
+                .thenReturn(IccCardConstants.State.NOT_READY)
+                .thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mCarrierTextController.updateCarrierText();
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+        assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER,
+                captor.getValue().carrierText);
+    }
+
     public static class TestCarrierTextController extends CarrierTextController {
         private KeyguardUpdateMonitor mKUM;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 40a5357..8b0ba94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bubbles;
 
+import static android.app.Notification.FLAG_BUBBLE;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -25,6 +26,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -47,15 +49,18 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -138,7 +143,7 @@
 
         // Some bubbles want to suppress notifs
         Notification.BubbleMetadata suppressNotifMetadata =
-                getBuilder().setSuppressInitialNotification(true).build();
+                getBuilder().setSuppressNotification(true).build();
         mSuppressNotifRow = mNotificationTestHelper.createBubble(suppressNotifMetadata,
                 FOREGROUND_TEST_PKG_NAME);
 
@@ -146,9 +151,15 @@
         when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
         when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel);
 
+        TestableNotificationInterruptionStateProvider interruptionStateProvider =
+                new TestableNotificationInterruptionStateProvider(mContext);
+        interruptionStateProvider.setUpWithPresenter(
+                mock(NotificationPresenter.class),
+                mock(HeadsUpManager.class),
+                mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
         mBubbleData = new BubbleData(mContext);
         mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
-                mBubbleData, mConfigurationController);
+                mBubbleData, mConfigurationController, interruptionStateProvider);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -487,12 +498,27 @@
         verify(mDeleteIntent, times(2)).send();
     }
 
+    @Test
+    public void testRemoveBubble_noLongerBubbleAfterUpdate()
+            throws PendingIntent.CanceledException {
+        mBubbleController.updateBubble(mRow.getEntry());
+        assertTrue(mBubbleController.hasBubbles());
+
+        mRow.getEntry().notification.getNotification().flags &= ~FLAG_BUBBLE;
+        mEntryListener.onPreEntryUpdated(mRow.getEntry());
+
+        assertFalse(mBubbleController.hasBubbles());
+        verify(mDeleteIntent, never()).send();
+    }
+
     static class TestableBubbleController extends BubbleController {
         // Let's assume surfaces can be synchronized immediately.
         TestableBubbleController(Context context,
                 StatusBarWindowController statusBarWindowController, BubbleData data,
-                ConfigurationController configurationController) {
-            super(context, statusBarWindowController, data, Runnable::run, configurationController);
+                ConfigurationController configurationController,
+                NotificationInterruptionStateProvider interruptionStateProvider) {
+            super(context, statusBarWindowController, data, Runnable::run,
+                    configurationController, interruptionStateProvider);
         }
 
         @Override
@@ -501,6 +527,15 @@
         }
     }
 
+    public static class TestableNotificationInterruptionStateProvider extends
+            NotificationInterruptionStateProvider {
+
+        public TestableNotificationInterruptionStateProvider(Context context) {
+            super(context);
+            mUseHeadsUp = true;
+        }
+    }
+
     /**
      * @return basic {@link android.app.Notification.BubbleMetadata.Builder}
      */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
new file mode 100644
index 0000000..26f1de8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2019 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.globalactions;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link ListGridLayout}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ListGridLayoutTest extends SysuiTestCase {
+
+    private ListGridLayout mListGridLayout;
+
+    @Before
+    public void setUp() throws Exception {
+        GlobalActionsGridLayout globalActions = (GlobalActionsGridLayout)
+                LayoutInflater.from(mContext).inflate(R.layout.global_actions_grid, null);
+        mListGridLayout = globalActions.getListView();
+    }
+
+    @Test
+    public void testInflation() {
+        assertEquals(3, mListGridLayout.getChildCount());
+    }
+
+    @Test
+    public void testGetRowCount() {
+        // above expected range
+        mListGridLayout.setExpectedCount(99);
+        assertEquals(3, mListGridLayout.getRowCount());
+
+        mListGridLayout.setExpectedCount(9);
+        assertEquals(3, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(8);
+        assertEquals(3, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(7);
+        assertEquals(3, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(6);
+        assertEquals(2, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(5);
+        assertEquals(2, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(4);
+        assertEquals(2, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(3);
+        assertEquals(1, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(2);
+        assertEquals(1, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(1);
+        assertEquals(1, mListGridLayout.getRowCount());
+        mListGridLayout.setExpectedCount(0);
+        assertEquals(0, mListGridLayout.getRowCount());
+
+        // below expected range
+        mListGridLayout.setExpectedCount(-1);
+        assertEquals(0, mListGridLayout.getRowCount());
+    }
+
+    @Test
+    public void testGetColumnCount() {
+        // above expected range
+        mListGridLayout.setExpectedCount(99);
+
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(9);
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(8);
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(7);
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(6);
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(5);
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(4);
+        assertEquals(2, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(3);
+        assertEquals(3, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(2);
+        assertEquals(2, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(1);
+        assertEquals(1, mListGridLayout.getColumnCount());
+        mListGridLayout.setExpectedCount(0);
+        assertEquals(0, mListGridLayout.getColumnCount());
+
+        // below expected range
+        mListGridLayout.setExpectedCount(-1);
+        assertEquals(0, mListGridLayout.getColumnCount());
+    }
+
+    @Test
+    public void testGetParentView_default() {
+        mListGridLayout.setExpectedCount(9);
+
+        // below valid range
+        assertEquals(null,
+                mListGridLayout.getParentView(-1, false, false));
+
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(0, false, false));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(1, false, false));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(2, false, false));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(3, false, false));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(4, false, false));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(5, false, false));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(6, false, false));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(7, false, false));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(8, false, false));
+
+        // above valid range
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(9, false, false));
+    }
+
+    @Test
+    public void testGetParentView_reverseSublists() {
+        mListGridLayout.setExpectedCount(9);
+
+        // below valid range
+        assertEquals(null,
+                mListGridLayout.getParentView(-1, true, false));
+
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(0, true, false));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(1, true, false));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(2, true, false));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(3, true, false));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(4, true, false));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(5, true, false));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(6, true, false));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(7, true, false));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(8, true, false));
+
+        // above valid range
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(9, true, false));
+    }
+
+    @Test
+    public void testGetParentView_swapRowsAndColumns() {
+        mListGridLayout.setExpectedCount(9);
+
+        // below valid range
+        assertEquals(null,
+                mListGridLayout.getParentView(-1, false, true));
+
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(0, false, true));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(1, false, true));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(2, false, true));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(3, false, true));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(4, false, true));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(5, false, true));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(6, false, true));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(7, false, true));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(8, false, true));
+
+        // above valid range
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(9, false, true));
+    }
+
+    @Test
+    public void testGetParentView_swapRowsAndColumnsAndReverseSublists() {
+        mListGridLayout.setExpectedCount(9);
+
+        // below valid range
+        assertEquals(null,
+                mListGridLayout.getParentView(-1, true, true));
+
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(0, true, true));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(1, true, true));
+        assertEquals(mListGridLayout.getChildAt(2),
+                mListGridLayout.getParentView(2, true, true));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(3, true, true));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(4, true, true));
+        assertEquals(mListGridLayout.getChildAt(1),
+                mListGridLayout.getParentView(5, true, true));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(6, true, true));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(7, true, true));
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(8, true, true));
+
+        // above valid range
+        assertEquals(mListGridLayout.getChildAt(0),
+                mListGridLayout.getParentView(9, true, true));
+    }
+
+    @Test
+    public void testRemoveAllItems() {
+        ViewGroup row1 = (ViewGroup) mListGridLayout.getChildAt(0);
+        ViewGroup row2 = (ViewGroup) mListGridLayout.getChildAt(1);
+        ViewGroup row3 = (ViewGroup) mListGridLayout.getChildAt(2);
+        View item1 = new View(mContext, null);
+        View item2 = new View(mContext, null);
+        View item3 = new View(mContext, null);
+
+        row1.addView(item1);
+        row2.addView(item2);
+        row3.addView(item3);
+
+        assertEquals(1, row1.getChildCount());
+        assertEquals(1, row2.getChildCount());
+        assertEquals(1, row3.getChildCount());
+
+        mListGridLayout.removeAllItems();
+
+        assertEquals(0, row1.getChildCount());
+        assertEquals(0, row2.getChildCount());
+        assertEquals(0, row2.getChildCount());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 5928a07..161b409 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -40,6 +40,7 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.testing.TestableResources;
 
+import com.android.settingslib.fuelgauge.Estimate;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.power.PowerUI.WarningsUI;
@@ -358,7 +359,7 @@
     @Test
     public void testRefreshEstimateIfNeeded_onlyQueriesEstimateOnBatteryLevelChangeOrNull() {
         mPowerUI.start();
-        Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
+        Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true, 0);
         when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
         when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
         when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
@@ -371,21 +372,21 @@
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
         BatteryStateSnapshot snapshot = new BatteryStateSnapshot(
                 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD,
-                0, 0, -1, 0, 0, false, true);
+                0, 0, -1, 0, 0, 0, false, true);
         mPowerUI.mLastBatteryStateSnapshot = snapshot;
 
         // query again since the estimate was -1
-        estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true);
+        estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true, 0);
         when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
         refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
         snapshot = new BatteryStateSnapshot(
                 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0,
-                0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false, true);
+                0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, 0, false, true);
         mPowerUI.mLastBatteryStateSnapshot = snapshot;
 
         // Battery level hasn't changed, so we don't query again
-        estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
+        estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true, 0);
         when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
         refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
@@ -543,13 +544,14 @@
         public boolean mIsBasedOnUsage = true;
         public boolean mIsHybrid = true;
         public boolean mIsLowLevelWarningEnabled = true;
+        private long mAverageTimeToDischargeMillis = Duration.ofHours(24).toMillis();
 
         public BatteryStateSnapshot get() {
             if (mIsHybrid) {
                 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
                         mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold,
-                        mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis,
-                        mIsBasedOnUsage, mIsLowLevelWarningEnabled);
+                        mTimeRemainingMillis, mAverageTimeToDischargeMillis, mSevereThresholdMillis,
+                        mLowThresholdMillis, mIsBasedOnUsage, mIsLowLevelWarningEnabled);
             } else {
                 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
                         mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 8cc1571..e4b90c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -178,7 +178,10 @@
         Notification n = createNotification(false /* isGroupSummary */,
                 null /* groupKey */, bubbleMetadata);
         n.flags |= FLAG_BUBBLE;
-        return generateRow(n, pkg, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH);
+        ExpandableNotificationRow row = generateRow(n, pkg, UID, USER_HANDLE,
+                0 /* extraInflationFlags */, IMPORTANCE_HIGH);
+        row.getEntry().canBubble = true;
+        return row;
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 6a0d61d..3ae57e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -14,18 +14,38 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.annotation.LayoutRes;
+import android.annotation.Nullable;
 import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
 import android.content.Context;
+import android.hardware.display.DisplayManagerGlobal;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Looper;
 import android.testing.AndroidTestingRunner;
 import android.testing.LeakCheck.Tracker;
+import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 
@@ -34,6 +54,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.SysuiTestableContext;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
@@ -50,9 +71,16 @@
 @RunWithLooper()
 @SmallTest
 public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
+    private static final int EXTERNAL_DISPLAY_ID = 2;
+    private static final int NAV_BAR_VIEW_ID = 43;
 
+    private Fragment mFragmentExternalDisplay;
+    private FragmentController mControllerExternalDisplay;
+
+    private SysuiTestableContext mSysuiTestableContextExternal;
     private OverviewProxyService mOverviewProxyService =
             mDependency.injectMockDependency(OverviewProxyService.class);
+    private CommandQueue mCommandQueue;
     private AccessibilityManagerWrapper mAccessibilityWrapper =
             new AccessibilityManagerWrapper(mContext) {
                 Tracker mTracker = mLeakCheck.getTracker("accessibility_manager");
@@ -73,15 +101,51 @@
     }
 
     protected void createRootView() {
-        mView = new NavigationBarFrame(mContext);
+        mView = new NavigationBarFrame(mSysuiContext);
+        mView.setId(NAV_BAR_VIEW_ID);
     }
 
     @Before
-    public void setup() {
-        mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+    public void setupFragment() throws Exception {
+        setupSysuiDependency();
+        createRootView();
+        TestableLooper.get(this).runWithLooper(() -> {
+            mHandler = new Handler();
+
+            mFragment = instantiate(mSysuiContext, NavigationBarFragment.class.getName(), null);
+            mFragments = FragmentController.createController(
+                    new HostCallbacksForExternalDisplay(mSysuiContext));
+            mFragments.attachHost(null);
+            mFragments.getFragmentManager().beginTransaction()
+                    .replace(NAV_BAR_VIEW_ID, mFragment)
+                    .commit();
+            mControllerExternalDisplay = FragmentController.createController(
+                    new HostCallbacksForExternalDisplay(mSysuiTestableContextExternal));
+            mControllerExternalDisplay.attachHost(null);
+            mFragmentExternalDisplay = instantiate(mSysuiTestableContextExternal,
+                    NavigationBarFragment.class.getName(), null);
+            mControllerExternalDisplay.getFragmentManager().beginTransaction()
+                    .replace(NAV_BAR_VIEW_ID, mFragmentExternalDisplay)
+                    .commit();
+        });
+    }
+
+    private void setupSysuiDependency() {
+        mCommandQueue = new CommandQueue(mContext);
+        mSysuiContext.putComponent(CommandQueue.class, mCommandQueue);
         mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
         mSysuiContext.putComponent(Recents.class, mock(Recents.class));
         mSysuiContext.putComponent(Divider.class, mock(Divider.class));
+
+        Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID,
+                new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
+        mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext(
+                display);
+        mSysuiTestableContextExternal.putComponent(CommandQueue.class, mCommandQueue);
+        mSysuiTestableContextExternal.putComponent(StatusBar.class, mock(StatusBar.class));
+        mSysuiTestableContextExternal.putComponent(Recents.class, mock(Recents.class));
+        mSysuiTestableContextExternal.putComponent(Divider.class, mock(Divider.class));
+
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         WindowManager windowManager = mock(WindowManager.class);
         Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
@@ -102,15 +166,111 @@
         navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
     }
 
+    @Test
+    public void testSetImeWindowStatusWhenImeSwitchOnDisplay() {
+        // Create default & external NavBar fragment.
+        NavigationBarFragment defaultNavBar = (NavigationBarFragment) mFragment;
+        NavigationBarFragment externalNavBar = (NavigationBarFragment) mFragmentExternalDisplay;
+        mFragments.dispatchCreate();
+        processAllMessages();
+        mFragments.dispatchResume();
+        processAllMessages();
+        mControllerExternalDisplay.dispatchCreate();
+        processAllMessages();
+        mControllerExternalDisplay.dispatchResume();
+        processAllMessages();
+
+        // Set IME window status for default NavBar.
+        mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
+                BACK_DISPOSITION_DEFAULT, true);
+        Handler.getMain().runWithScissors(() -> { }, 500);
+
+        // Verify IME window state will be updated in default NavBar & external NavBar state reset.
+        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
+                defaultNavBar.getNavigationIconHints());
+        assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+        assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+
+        // Set IME window status for external NavBar.
+        mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null,
+                IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true);
+        Handler.getMain().runWithScissors(() -> { }, 500);
+
+        // Verify IME window state will be updated in external NavBar & default NavBar state reset.
+        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
+                externalNavBar.getNavigationIconHints());
+        assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+        assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+    }
+
     @Override
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
         DeviceProvisionedController deviceProvisionedController =
                 mock(DeviceProvisionedController.class);
         assertNotNull(mAccessibilityWrapper);
-        return new NavigationBarFragment(mAccessibilityWrapper,
+        return new NavigationBarFragment(
+                context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper
+                        : mock(AccessibilityManagerWrapper.class),
                 deviceProvisionedController,
                 new MetricsLogger(),
-                new AssistManager(deviceProvisionedController, mContext),
+                mock(AssistManager.class),
                 mOverviewProxyService);
     }
+
+    private class HostCallbacksForExternalDisplay extends
+            FragmentHostCallback<NavigationBarFragmentTest> {
+        private Context mDisplayContext;
+
+        HostCallbacksForExternalDisplay(Context context) {
+            super(context, mHandler, 0);
+            mDisplayContext = context;
+        }
+
+        @Override
+        public NavigationBarFragmentTest onGetHost() {
+            return NavigationBarFragmentTest.this;
+        }
+
+        @Override
+        public Fragment instantiate(Context context, String className, Bundle arguments) {
+            return NavigationBarFragmentTest.this.instantiate(context, className, arguments);
+        }
+
+        @Override
+        public View onFindViewById(int id) {
+            return mView.findViewById(id);
+        }
+
+        @Override
+        public LayoutInflater onGetLayoutInflater() {
+            return new LayoutInflaterWrapper(mDisplayContext);
+        }
+    }
+
+    private static class LayoutInflaterWrapper extends LayoutInflater {
+        protected LayoutInflaterWrapper(Context context) {
+            super(context);
+        }
+
+        @Override
+        public LayoutInflater cloneInContext(Context newContext) {
+            return null;
+        }
+
+        @Override
+        public View inflate(@LayoutRes int resource, @Nullable ViewGroup root,
+                boolean attachToRoot) {
+            NavigationBarView view = mock(NavigationBarView.class);
+            when(view.getDisplay()).thenReturn(mContext.getDisplay());
+            when(view.getBackButton()).thenReturn(mock(ButtonDispatcher.class));
+            when(view.getHomeButton()).thenReturn(mock(ButtonDispatcher.class));
+            when(view.getRecentsButton()).thenReturn(mock(ButtonDispatcher.class));
+            when(view.getAccessibilityButton()).thenReturn(mock(ButtonDispatcher.class));
+            when(view.getRotateSuggestionButton()).thenReturn(mock(RotationContextButton.class));
+            when(view.getBarTransitions()).thenReturn(mock(BarTransitions.class));
+            when(view.getLightTransitionsController()).thenReturn(
+                    mock(LightBarTransitionsController.class));
+            return view;
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 43bc21b..fb16465 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -681,6 +681,25 @@
     }
 
     @Test
+    public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() {
+        // Keep track of callback to be able to stop the pulse
+        final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
+        doAnswer(invocation -> {
+            pulseCallback[0] = invocation.getArgument(0);
+            return null;
+        }).when(mDozeScrimController).pulse(any(), anyInt());
+
+        // Starting a pulse while docking should suppress wakeup gesture
+        mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
+                DozeLog.PULSE_REASON_DOCKING);
+        verify(mStatusBarWindowView).suppressWakeUpGesture(eq(true));
+
+        // Ending a pulse should restore wakeup gesture
+        pulseCallback[0].onPulseFinished();
+        verify(mStatusBarWindowView).suppressWakeUpGesture(eq(false));
+    }
+
+    @Test
     public void testSetState_changesIsFullScreenUserSwitcherState() {
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         assertFalse(mStatusBar.isFullScreenUserSwitcherState());
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 55a0621..ecea251c 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -16,7 +16,9 @@
 
 package com.android.server.contentsuggestions;
 
+import static android.Manifest.permission.BIND_CONTENT_SUGGESTIONS_SERVICE;
 import static android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -92,16 +94,11 @@
         return MAX_TEMP_SERVICE_DURATION_MS;
     }
 
-    private boolean isCallerRecents(int userId) {
-        if (mServiceNameResolver.isTemporary(userId)) {
-            // If a temporary service is set then skip the recents check
-            return true;
-        }
-        return mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid());
-    }
-
-    private void enforceCallerIsRecents(int userId, String func) {
-        if (isCallerRecents(userId)) {
+    private void enforceCaller(int userId, String func) {
+        Context ctx = getContext();
+        if (ctx.checkCallingPermission(BIND_CONTENT_SUGGESTIONS_SERVICE) == PERMISSION_GRANTED
+                || mServiceNameResolver.isTemporary(userId)
+                || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) {
             return;
         }
 
@@ -122,7 +119,7 @@
             if (imageContextRequestExtras == null) {
                 throw new IllegalArgumentException("Expected non-null imageContextRequestExtras");
             }
-            enforceCallerIsRecents(UserHandle.getCallingUserId(), "provideContextImage");
+            enforceCaller(UserHandle.getCallingUserId(), "provideContextImage");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -141,7 +138,7 @@
                 int userId,
                 @NonNull SelectionsRequest selectionsRequest,
                 @NonNull ISelectionsCallback selectionsCallback) {
-            enforceCallerIsRecents(UserHandle.getCallingUserId(), "suggestContentSelections");
+            enforceCaller(UserHandle.getCallingUserId(), "suggestContentSelections");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -160,7 +157,7 @@
                 int userId,
                 @NonNull ClassificationsRequest classificationsRequest,
                 @NonNull IClassificationsCallback callback) {
-            enforceCallerIsRecents(UserHandle.getCallingUserId(), "classifyContentSelections");
+            enforceCaller(UserHandle.getCallingUserId(), "classifyContentSelections");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -177,7 +174,7 @@
         @Override
         public void notifyInteraction(
                 int userId, @NonNull String requestId, @NonNull Bundle bundle) {
-            enforceCallerIsRecents(UserHandle.getCallingUserId(), "notifyInteraction");
+            enforceCaller(UserHandle.getCallingUserId(), "notifyInteraction");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -194,7 +191,7 @@
         @Override
         public void isEnabled(int userId, @NonNull IResultReceiver receiver)
                 throws RemoteException {
-            enforceCallerIsRecents(UserHandle.getCallingUserId(), "isEnabled");
+            enforceCaller(UserHandle.getCallingUserId(), "isEnabled");
 
             boolean isDisabled;
             synchronized (mLock) {
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index e65a4e5..7c2ea3f 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -139,3 +139,8 @@
 
 # The task is being compacted
 30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(DeltaRssTotal|2|2),(DeltaRssFile|2|2),(DeltaRssAnon|2|2),(DeltaRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(DeltaZRAMFree|2|2)
+
+# The activity's onTopResumedActivityChanged(true) has been called.
+30064 am_on_top_resumed_gained_called (User|1|5),(Component Name|3),(Reason|3)
+# The activity's onTopResumedActivityChanged(false) has been called.
+30065 am_on_top_resumed_lost_called (User|1|5),(Component Name|3),(Reason|3)
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d30a9d2..2d00f29 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -508,13 +508,14 @@
     // Used to play ringtones outside system_server
     private volatile IRingtonePlayer mRingtonePlayer;
 
-    // Devices for which the volume is fixed and VolumePanel slider should be disabled
+    // Devices for which the volume is fixed (volume is either max or muted)
     int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
             AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
             AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
             AudioSystem.DEVICE_OUT_HDMI_ARC |
             AudioSystem.DEVICE_OUT_SPDIF |
             AudioSystem.DEVICE_OUT_AUX_LINE;
+    // Devices for which the volume is always max, no volume panel
     int mFullVolumeDevices = 0;
 
     private final boolean mMonitorRotation;
@@ -859,6 +860,11 @@
                     mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
                 }
                 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
+                if (mHdmiPlaybackClient != null) {
+                    // not a television: HDMI output will be always at max
+                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
+                    mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+                }
                 mHdmiCecSink = false;
                 mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
             }
@@ -1065,7 +1071,6 @@
             }
 
             if (isPlatformTelevision()) {
-                mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
                 checkAllFixedVolumeDevices();
                 synchronized (mHdmiClientLock) {
                     if (mHdmiManager != null && mHdmiPlaybackClient != null) {
@@ -1656,7 +1661,7 @@
 
         flags &= ~AudioManager.FLAG_FIXED_VOLUME;
         if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-               ((device & mFixedVolumeDevices) != 0)) {
+                ((device & mFixedVolumeDevices) != 0)) {
             flags |= AudioManager.FLAG_FIXED_VOLUME;
 
             // Always toggle between max safe volume and 0 for fixed volume devices where safe
@@ -1733,8 +1738,9 @@
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
                 mVolumeController.postDisplaySafeVolumeWarning(flags);
-            } else if (streamState.adjustIndex(direction * step, device, caller)
-                    || streamState.mIsMuted) {
+            } else if (((device & mFullVolumeDevices) == 0)
+                    && (streamState.adjustIndex(direction * step, device, caller)
+                            || streamState.mIsMuted)) {
                 // Post message to set system volume (it in turn will post a
                 // message to persist).
                 if (streamState.mIsMuted) {
@@ -1785,9 +1791,10 @@
             synchronized (mHdmiClientLock) {
                 if (mHdmiManager != null) {
                     // mHdmiCecSink true => mHdmiPlaybackClient != null
-                    if (mHdmiCecSink &&
-                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                            oldIndex != newIndex) {
+                    if (mHdmiCecSink
+                            && streamTypeAlias == AudioSystem.STREAM_MUSIC
+                            // vol change on a full volume device
+                            && ((device & mFullVolumeDevices) != 0)) {
                         int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
                                 KeyEvent.KEYCODE_VOLUME_UP;
                         final long ident = Binder.clearCallingIdentity();
@@ -1814,7 +1821,7 @@
             }
         }
         int index = mStreamStates[streamType].getIndex(device);
-        sendVolumeUpdate(streamType, oldIndex, index, flags);
+        sendVolumeUpdate(streamType, oldIndex, index, flags, device);
     }
 
     // Called after a delay when volume down is pressed while muted
@@ -1824,7 +1831,7 @@
 
         final int device = getDeviceForStream(stream);
         final int index = mStreamStates[stream].getIndex(device);
-        sendVolumeUpdate(stream, index, index, flags);
+        sendVolumeUpdate(stream, index, index, flags, device);
     }
 
     private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
@@ -1835,7 +1842,9 @@
                     || mHdmiTvClient == null
                     || oldVolume == newVolume
                     || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0
-                    || !mHdmiSystemAudioSupported) return;
+                    || !mHdmiSystemAudioSupported) {
+                return;
+            }
             final long token = Binder.clearCallingIdentity();
             try {
                 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
@@ -2149,7 +2158,7 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
-        sendVolumeUpdate(streamType, oldIndex, index, flags);
+        sendVolumeUpdate(streamType, oldIndex, index, flags, device);
     }
 
 
@@ -2303,18 +2312,22 @@
     }
 
     // UI update and Broadcast Intent
-    protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
+    protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags, int device)
+    {
         streamType = mStreamVolumeAlias[streamType];
 
         if (streamType == AudioSystem.STREAM_MUSIC) {
-            flags = updateFlagsForSystemAudio(flags);
+            flags = updateFlagsForTvPlatform(flags);
+            if ((device & mFullVolumeDevices) != 0) {
+                flags &= ~AudioManager.FLAG_SHOW_UI;
+            }
         }
         mVolumeController.postVolumeChanged(streamType, flags);
     }
 
     // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
     // receives volume notification from Audio Receiver.
-    private int updateFlagsForSystemAudio(int flags) {
+    private int updateFlagsForTvPlatform(int flags) {
         synchronized (mHdmiClientLock) {
             if (mHdmiTvClient != null) {
                 if (mHdmiSystemAudioSupported &&
@@ -2328,7 +2341,7 @@
 
     // UI update and Broadcast Intent
     private void sendMasterMuteUpdate(boolean muted, int flags) {
-        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
+        mVolumeController.postMasterMuteChanged(updateFlagsForTvPlatform(flags));
         broadcastMasterMuteStatus(muted);
     }
 
@@ -2355,6 +2368,9 @@
                                     int device,
                                     boolean force,
                                     String caller) {
+        if ((device & mFullVolumeDevices) != 0) {
+            return;
+        }
         VolumeStreamState streamState = mStreamStates[streamType];
 
         if (streamState.setIndex(index, device, caller) || force) {
@@ -5810,9 +5826,14 @@
     }
 
     //==========================================================================================
-    // Hdmi Cec system audio mode.
-    // If Hdmi Cec's system audio mode is on, audio service should send the volume change
-    // to HdmiControlService so that the audio receiver can handle it.
+    // Hdmi CEC:
+    // - System audio mode:
+    //     If Hdmi Cec's system audio mode is on, audio service should send the volume change
+    //     to HdmiControlService so that the audio receiver can handle it.
+    // - CEC sink:
+    //     OUT_HDMI becomes a "full volume device", i.e. output is always at maximum level
+    //     and volume changes won't be taken into account on this device. Volume adjustments
+    //     are transformed into key events for the HDMI playback client.
     //==========================================================================================
 
     private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
@@ -5821,8 +5842,18 @@
                 if (mHdmiManager != null) {
                     mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
                     // Television devices without CEC service apply software volume on HDMI output
-                    if (isPlatformTelevision() && !mHdmiCecSink) {
-                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
+                    if (mHdmiCecSink) {
+                        if (DEBUG_VOL) {
+                            Log.d(TAG, "CEC sink: setting HDMI as full vol device");
+                        }
+                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+                    } else {
+                        if (DEBUG_VOL) {
+                            Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
+                        }
+                        // Android TV devices without CEC service apply software volume on
+                        // HDMI output
+                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
                     }
                     checkAllFixedVolumeDevices();
                 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3c97c39..c2aade3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -575,6 +575,12 @@
      */
     int mCurTokenDisplayId = INVALID_DISPLAY;
 
+    /**
+     * The display ID of the input method indicates the fallback display which returned by
+     * {@link #computeImeDisplayIdForTarget}.
+     */
+    private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
+
     final ImeDisplayValidator mImeDisplayValidator;
 
     /**
@@ -625,7 +631,8 @@
      *    currently invisible.
      * </dd>
      * </dl>
-     * <em>Do not update this value outside of setImeWindowStatus.</em>
+     * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
+     * {@link #unbindCurrentMethodLocked()}.</em>
      */
     int mImeWindowVis;
 
@@ -2124,12 +2131,10 @@
      */
     static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
         if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
-            // We always assume that the default display id suitable to show the IME window.
-            return DEFAULT_DISPLAY;
+            return FALLBACK_DISPLAY_ID;
         }
-        // Show IME in default display when the display with IME target doesn't support system
-        // decorations.
-        return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
+        // Show IME window on fallback display when the display is not allowed.
+        return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
     }
 
     @Override
@@ -2198,6 +2203,10 @@
                 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
+            // Set IME window status as invisible when unbind current method.
+            mImeWindowVis = 0;
+            mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+            updateSystemUiLocked(mImeWindowVis, mBackDisposition);
             mCurToken = null;
             mCurTokenDisplayId = INVALID_DISPLAY;
         }
@@ -2399,10 +2408,20 @@
     @BinderThread
     @SuppressWarnings("deprecation")
     private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
+        final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
+
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
+            // Skip update IME status when current token display is not same as focused display.
+            // Note that we still need to update IME status when focusing external display
+            // that does not support system decoration and fallback to show IME on default
+            // display since it is intentional behavior.
+            if (mCurTokenDisplayId != topFocusedDisplayId
+                    && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
+                return;
+            }
             mImeWindowVis = vis;
             mBackDisposition = backDisposition;
             updateSystemUiLocked(vis, backDisposition);
@@ -2447,7 +2466,8 @@
         if (DEBUG) {
             Slog.d(TAG, "IME window vis: " + vis
                     + " active: " + (vis & InputMethodService.IME_ACTIVE)
-                    + " inv: " + (vis & InputMethodService.IME_INVISIBLE));
+                    + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
+                    + " displayId: " + mCurTokenDisplayId);
         }
 
         // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
@@ -2461,7 +2481,7 @@
             // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
             final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
             if (mStatusBar != null) {
-                mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition,
+                mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
                         needsToShowImeSwitcher);
             }
             final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 8578bb7..a349d87 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -248,7 +248,8 @@
             scheduleOpTimeOutLocked();
             final Intent intent = new Intent().setComponent(job.getServiceComponent());
             boolean binding = mContext.bindServiceAsUser(intent, this,
-                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+                    | Context.BIND_NOT_VISIBLE | Context.BIND_ADJUST_BELOW_PERCEPTIBLE,
                     new UserHandle(job.getUserId()));
             if (!binding) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6c11157..2e8e65b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -308,8 +308,7 @@
     static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
             Adjustment.KEY_IMPORTANCE,
             Adjustment.KEY_CONTEXTUAL_ACTIONS,
-            Adjustment.KEY_TEXT_REPLIES,
-            Adjustment.KEY_USER_SENTIMENT};
+            Adjustment.KEY_TEXT_REPLIES};
 
     static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
             RoleManager.ROLE_DIALER,
@@ -7325,7 +7324,7 @@
 
         private static final String ATT_USER_SET = "user_set";
         // TODO: STOPSHIP (b/127994217) switch to final value when onboarding flow is implemented
-        private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments_tmp";
+        private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments_tmp2";
         private static final String ATT_TYPES = "types";
 
         private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1f5b99c..981e0f5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -940,13 +940,34 @@
         }
     }
 
+    private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) {
+        if (rule.zenMode == NotificationManager.INTERRUPTION_FILTER_NONE) {
+            policy.apply(new ZenPolicy.Builder()
+                    .disallowAllSounds()
+                    .build());
+        } else if (rule.zenMode
+                == NotificationManager.INTERRUPTION_FILTER_ALARMS) {
+            policy.apply(new ZenPolicy.Builder()
+                    .disallowAllSounds()
+                    .allowAlarms(true)
+                    .allowMedia(true)
+                    .build());
+        } else {
+            policy.apply(rule.zenPolicy);
+        }
+    }
+
     private void updateConsolidatedPolicy(String reason) {
         if (mConfig == null) return;
         synchronized (mConfig) {
             ZenPolicy policy = new ZenPolicy();
+            if (mConfig.manualRule != null) {
+                applyCustomPolicy(policy, mConfig.manualRule);
+            }
+
             for (ZenRule automaticRule : mConfig.automaticRules.values()) {
                 if (automaticRule.isAutomaticActive()) {
-                    policy.apply(automaticRule.zenPolicy);
+                    applyCustomPolicy(policy, automaticRule);
                 }
             }
             Policy newPolicy = mConfig.toNotificationPolicy(policy);
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 2280d3f..05e9b93 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -1,14 +1,6 @@
 {
     "presubmit": [
         {
-            "name": "GtsPermissionTestCases",
-            "options": [
-                {
-                    "include-filter": "com.google.android.permission.gts.DefaultPermissionGrantPolicyTest"
-                }
-            ]
-        },
-        {
             "name": "CtsPermissionTestCases",
             "options": [
                 {
@@ -31,4 +23,4 @@
             ]
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d0ca861..9b4293d48 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -256,6 +256,7 @@
     // Whether to allow devices placed in vr headset viewers to have an alternative Home intent.
     static final boolean ENABLE_VR_HEADSET_HOME_CAPTURE = true;
 
+    // must match: config_shortPressOnPowerBehavior in config.xml
     static final int SHORT_PRESS_POWER_NOTHING = 0;
     static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -263,29 +264,34 @@
     static final int SHORT_PRESS_POWER_GO_HOME = 4;
     static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5;
 
+    // must match: config_LongPressOnPowerBehavior in config.xml
     static final int LONG_PRESS_POWER_NOTHING = 0;
     static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
     static final int LONG_PRESS_POWER_SHUT_OFF = 2;
     static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
     static final int LONG_PRESS_POWER_GO_TO_VOICE_ASSIST = 4;
+    static final int LONG_PRESS_POWER_ASSISTANT = 5; // Settings.Secure.ASSISTANT
 
+    // must match: config_veryLongPresOnPowerBehavior in config.xml
     static final int VERY_LONG_PRESS_POWER_NOTHING = 0;
     static final int VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
 
+    // must match: config_doublePressOnPowerBehavior in config.xml
     static final int MULTI_PRESS_POWER_NOTHING = 0;
     static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
     static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
 
+    // must match: config_longPressOnBackBehavior in config.xml
     static final int LONG_PRESS_BACK_NOTHING = 0;
     static final int LONG_PRESS_BACK_GO_TO_VOICE_ASSIST = 1;
 
-    // These need to match the documentation/constant in
-    // core/res/res/values/config.xml
+    // must match: config_longPressOnHomeBehavior in config.xml
     static final int LONG_PRESS_HOME_NOTHING = 0;
     static final int LONG_PRESS_HOME_ALL_APPS = 1;
     static final int LONG_PRESS_HOME_ASSIST = 2;
     static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_ASSIST;
 
+    // must match: config_doubleTapOnHomeBehavior in config.xml
     static final int DOUBLE_TAP_HOME_NOTHING = 0;
     static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
 
@@ -770,6 +776,12 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POWER_BUTTON_LONG_PRESS), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POWER_BUTTON_VERY_LONG_PRESS), false, this,
+                    UserHandle.USER_ALL);
             updateSettings();
         }
 
@@ -1195,38 +1207,38 @@
     private void powerLongPress() {
         final int behavior = getResolvedLongPressOnPowerBehavior();
         switch (behavior) {
-        case LONG_PRESS_POWER_NOTHING:
-            break;
-        case LONG_PRESS_POWER_GLOBAL_ACTIONS:
-            mPowerKeyHandled = true;
-            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
-                    "Power - Long Press - Global Actions");
-            showGlobalActionsInternal();
-            break;
-        case LONG_PRESS_POWER_SHUT_OFF:
-        case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
-            mPowerKeyHandled = true;
-            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
-                    "Power - Long Press - Shut Off");
-            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-            mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
-            break;
-        case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
-            mPowerKeyHandled = true;
-            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
-                    "Power - Long Press - Go To Voice Assist");
-            final boolean keyguardActive = mKeyguardDelegate == null
-                    ? false
-                    : mKeyguardDelegate.isShowing();
-            if (!keyguardActive) {
-                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
-                if (mAllowStartActivityForLongPressOnPowerDuringSetup) {
-                    mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
-                } else {
-                    startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
-                }
-            }
-            break;
+            case LONG_PRESS_POWER_NOTHING:
+                break;
+            case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+                mPowerKeyHandled = true;
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                        "Power - Long Press - Global Actions");
+                showGlobalActionsInternal();
+                break;
+            case LONG_PRESS_POWER_SHUT_OFF:
+            case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
+                mPowerKeyHandled = true;
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                        "Power - Long Press - Shut Off");
+                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+                mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
+                break;
+            case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
+                mPowerKeyHandled = true;
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                        "Power - Long Press - Go To Voice Assist");
+                // Some devices allow the voice assistant intent during setup (and use that intent
+                // to launch something else, like Settings). So we explicitly allow that via the
+                // config_allowStartActivityForLongPressOnPowerInSetup resource in config.xml.
+                launchVoiceAssist(mAllowStartActivityForLongPressOnPowerDuringSetup);
+                break;
+            case LONG_PRESS_POWER_ASSISTANT:
+                mPowerKeyHandled = true;
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                        "Power - Long Press - Go To Assistant");
+                final int powerKeyDeviceId = Integer.MIN_VALUE;
+                launchAssistAction(null, powerKeyDeviceId);
+                break;
         }
     }
 
@@ -1250,13 +1262,7 @@
             case LONG_PRESS_BACK_NOTHING:
                 break;
             case LONG_PRESS_BACK_GO_TO_VOICE_ASSIST:
-                final boolean keyguardActive = mKeyguardDelegate == null
-                        ? false
-                        : mKeyguardDelegate.isShowing();
-                if (!keyguardActive) {
-                    Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
-                    startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
-                }
+                launchVoiceAssist(false /* allowDuringSetup */);
                 break;
         }
     }
@@ -1999,6 +2005,15 @@
                 mHasSoftInput = hasSoftInput;
                 updateRotation = true;
             }
+
+            mLongPressOnPowerBehavior = Settings.Global.getInt(resolver,
+                    Settings.Global.POWER_BUTTON_LONG_PRESS,
+                    mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_longPressOnPowerBehavior));
+            mVeryLongPressOnPowerBehavior = Settings.Global.getInt(resolver,
+                    Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
+                    mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_veryLongPressOnPowerBehavior));
         }
         if (updateRotation) {
             updateRotation(true);
@@ -3225,6 +3240,10 @@
         return 0;
     }
 
+    // There are several different flavors of "assistant" that can be launched from
+    // various parts of the UI.
+
+    /** starts ACTION_SEARCH_LONG_PRESS, usually a voice search prompt */
     private void launchAssistLongPressAction() {
         performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
                 "Assist - Long Press");
@@ -3246,6 +3265,7 @@
         }
     }
 
+    /** Asks the status bar to startAssist(), usually a full "assistant" interface */
     private void launchAssistAction(String hint, int deviceId) {
         sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
         if (!isUserSetupComplete()) {
@@ -3276,12 +3296,30 @@
         }
     }
 
+    /** Launches ACTION_VOICE_ASSIST. Does nothing on keyguard. */
+    private void launchVoiceAssist(boolean allowDuringSetup) {
+        final boolean keyguardActive = mKeyguardDelegate == null
+                ? false
+                : mKeyguardDelegate.isShowing();
+        if (!keyguardActive) {
+            Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+            startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
+                    allowDuringSetup);
+        }
+
+    }
+
     private void startActivityAsUser(Intent intent, UserHandle handle) {
         startActivityAsUser(intent, null, handle);
     }
 
     private void startActivityAsUser(Intent intent, Bundle bundle, UserHandle handle) {
-        if (isUserSetupComplete()) {
+        startActivityAsUser(intent, bundle, handle, false /* allowDuringSetup */);
+    }
+
+    private void startActivityAsUser(Intent intent, Bundle bundle, UserHandle handle,
+            boolean allowDuringSetup) {
+        if (allowDuringSetup || isUserSetupComplete()) {
             mContext.startActivityAsUser(intent, bundle, handle);
         } else {
             Slog.i(TAG, "Not starting activity because user setup is in progress: " + intent);
@@ -5541,6 +5579,10 @@
                 return "LONG_PRESS_POWER_SHUT_OFF";
             case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
                 return "LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM";
+            case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
+                return "LONG_PRESS_POWER_GO_TO_VOICE_ASSIST";
+            case LONG_PRESS_POWER_ASSISTANT:
+                return "LONG_PRESS_POWER_ASSISTANT";
             default:
                 return Integer.toString(behavior);
         }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 0caeb10..1edb93a 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -2563,9 +2563,8 @@
     private static final class ThermalEventListener extends IThermalEventListener.Stub {
         @Override
         public void notifyThrottling(Temperature temp) {
-            StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
-                    StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__UNKNOWN,
-                    temp.getValue(), temp.getStatus(), temp.getName());
+            StatsLog.write(StatsLog.THERMAL_THROTTLING_SEVERITY_STATE_CHANGED, temp.getType(),
+                    temp.getName(), (int) (temp.getValue() * 10), temp.getStatus());
         }
     }
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index aaf3df3..9cbf00b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -843,10 +843,9 @@
         }
     }
 
-    // TODO(b/117478341): support back button change when IME is showing on a external display.
     @Override
-    public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
-            final boolean showImeSwitcher) {
+    public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
+            final int backDisposition, final boolean showImeSwitcher) {
         enforceStatusBar();
 
         if (SPEW) {
@@ -857,18 +856,13 @@
             // In case of IME change, we need to call up setImeWindowStatus() regardless of
             // mImeWindowVis because mImeWindowVis may not have been set to false when the
             // previous IME was destroyed.
-            // TODO(b/117478341): support back button change when IME is showing on a external
-            // display.
-            getUiState(DEFAULT_DISPLAY)
-                    .setImeWindowState(vis, backDisposition, showImeSwitcher, token);
+            getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher, token);
 
             mHandler.post(() -> {
                 if (mBar == null) return;
                 try {
-                    // TODO(b/117478341): support back button change when IME is showing on a
-                    // external display.
                     mBar.setImeWindowStatus(
-                            DEFAULT_DISPLAY, token, vis, backDisposition, showImeSwitcher);
+                            displayId, token, vis, backDisposition, showImeSwitcher);
                 } catch (RemoteException ex) { }
             });
         }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 0ebd092..6ce42ec 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1132,7 +1132,7 @@
                 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
 
                 // Iterate until we figure out what is touchable for the entire screen.
-                for (int i = visibleWindowCount - 1; i >= 0 && !unaccountedSpace.isEmpty(); i--) {
+                for (int i = visibleWindowCount - 1; i >= 0; i--) {
                     final WindowState windowState = visibleWindows.valueAt(i);
 
                     final Rect boundsInScreen = mTempRect;
@@ -1143,6 +1143,11 @@
                         addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
                         updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace,
                                 skipRemainingWindowsForTasks);
+                        focusedWindowAdded |= windowState.isFocused();
+                    }
+
+                    if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
+                        break;
                     }
                 }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 76b0351..4ed07c3 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -4089,11 +4089,14 @@
         // The activity that we are finishing may be over the lock screen. In this case, we do not
         // want to consider activities that cannot be shown on the lock screen as running and should
         // proceed with finishing the activity if there is no valid next top running activity.
+        // Note that if this finishing activity is floating task, we don't need to wait the
+        // next activity resume and can destroy it directly.
         final ActivityDisplay display = getDisplay();
         final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */);
+        final boolean isFloating = r.getConfiguration().windowConfiguration.tasksAreFloating();
 
         if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
-                && next != null && !next.nowVisible) {
+                && next != null && !next.nowVisible && !isFloating) {
             if (!mStackSupervisor.mStoppingActivities.contains(r)) {
                 addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */);
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 9d80425..78c5dbd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -476,6 +476,11 @@
     public abstract int getDisplayIdForWindow(IBinder windowToken);
 
     /**
+     * @return The top focused display ID.
+     */
+    public abstract int getTopFocusedDisplayId();
+
+    /**
      * Checks whether this display should support showing system decorations.
      */
     public abstract boolean shouldShowSystemDecorOnDisplay(int displayId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8ed2a15..d46aa7b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7340,6 +7340,13 @@
         }
 
         @Override
+        public int getTopFocusedDisplayId() {
+            synchronized (mGlobalLock) {
+                return mRoot.getTopFocusedDisplayContent().getDisplayId();
+            }
+        }
+
+        @Override
         public boolean shouldShowSystemDecorOnDisplay(int displayId) {
             synchronized (mGlobalLock) {
                 return WindowManagerService.this.shouldShowSystemDecors(displayId);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8e18683..4105487 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2861,6 +2861,13 @@
             }
             mDestroying = false;
             destroyedSomething = true;
+
+            // Since mDestroying will affect AppWindowToken#allDrawn, we need to perform another
+            // traversal in case we are waiting on this window to start the transition.
+            if (getDisplayContent().mAppTransition.isTransitionSet()
+                    && getDisplayContent().mOpeningApps.contains(mAppToken)) {
+                mWmService.mWindowPlacerLocked.requestTraversal();
+            }
         }
 
         return destroyedSomething;
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 9f60cce..6cd88b5 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -52,7 +52,7 @@
 
     private static final int VIEW_ID = 42;
     private final Class<? extends Fragment> mCls;
-    private Handler mHandler;
+    protected Handler mHandler;
     protected FrameLayout mView;
     protected FragmentController mFragments;
     protected Fragment mFragment;