Merge "Disable blocking helper" into qt-dev
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/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/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/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/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_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/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/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/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/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/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/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/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/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 2e8e65b..e5ecd49 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2863,8 +2863,7 @@
 
             // Reset notification preferences
             if (!fromApp) {
-                mPreferencesHelper.onPackagesChanged(
-                        true, UserHandle.getCallingUserId(), packages, uids);
+                mPreferencesHelper.clearData(packageName, uid);
             }
 
             handleSavePolicyFile();
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 642fa7f..b57063f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1717,6 +1717,22 @@
         }
     }
 
+    public void clearData(String pkg, int uid) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences p = getPackagePreferencesLocked(pkg, uid);
+            p.channels = new ArrayMap<>();
+            p.groups = new ArrayMap<>();
+            p.delegate = null;
+            p.lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+            p.allowBubble = DEFAULT_ALLOW_BUBBLE;
+            p.importance = DEFAULT_IMPORTANCE;
+            p.priority = DEFAULT_PRIORITY;
+            p.visibility = DEFAULT_VISIBILITY;
+            p.showBadge = DEFAULT_SHOW_BADGE;
+
+        }
+    }
+
     private LogMaker getChannelLog(NotificationChannel channel, String pkg) {
         return new LogMaker(
                 com.android.internal.logging.nano.MetricsProto.MetricsEvent
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/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/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index b34bd25..1a06490 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -1644,6 +1644,38 @@
     }
 
     @Test
+    public void testClearData() {
+        ArraySet<String> pkg = new ArraySet<>();
+        pkg.add(PKG_O);
+        mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
+        mHelper.createNotificationChannelGroup(
+                PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true);
+        mHelper.lockChannelsForOEM(pkg.toArray(new String[]{}));
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkg);
+        mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1);
+        mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
+        mHelper.setBubblesAllowed(PKG_O, UID_O, false);
+        mHelper.setShowBadge(PKG_O, UID_O, false);
+        mHelper.setAppImportanceLocked(PKG_O, UID_O);
+
+        mHelper.clearData(PKG_O, UID_O);
+
+        assertEquals(IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_O, UID_O));
+        assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
+        assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
+        assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+        assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
+        assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size());
+
+        NotificationChannel channel = getChannel();
+        mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+        assertTrue(channel.isImportanceLockedByCriticalDeviceFunction());
+        assertTrue(channel.isImportanceLockedByOEM());
+    }
+
+    @Test
     public void testRecordDefaults() throws Exception {
         assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
                 UID_N_MR1));
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;