Merge "Revert "Use the SubId in the TM.getNetworkType if Valid"" into qt-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ca04536a..4e1bcc1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -123,7 +123,6 @@
 import android.renderscript.RenderScriptCacheDir;
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
-import android.service.voice.VoiceInteractionSession;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.system.StructStat;
@@ -5627,6 +5626,16 @@
         }
     }
 
+    /**
+     * Updates the application info.
+     *
+     * This only works in the system process. Must be called on the main thread.
+     */
+    public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) {
+        Preconditions.checkState(mSystemThread, "Must only be called in the system process");
+        handleApplicationInfoChanged(ai);
+    }
+
     @VisibleForTesting(visibility = PACKAGE)
     public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
         // Updates triggered by package installation go through a package update
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 66ddf21..6178b2b 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -1033,6 +1033,8 @@
                     Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
                 }
             } else {
+                // Clear the parcel before writing the exception
+                reply.setDataSize(0);
                 reply.setDataPosition(0);
                 reply.writeException(e);
             }
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 80b1607..7d287e3 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -175,12 +175,10 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(mFd);
-        try {
-            // Don't let writing to a parcel to close our fd - plz
-            parcel.writeParcelable(pfd, flags & ~Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } finally {
-            pfd.detachFd();
+        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(mFd)) {
+            parcel.writeParcelable(pfd, flags);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
         }
     }
 
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 616c4b5..b7dd88b 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -175,6 +175,9 @@
             if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
                 final String timeZone = intent.getStringExtra("time-zone");
                 createTime(timeZone);
+            } else if (!mShouldRunTicker && (Intent.ACTION_TIME_TICK.equals(intent.getAction())
+                    || Intent.ACTION_TIME_CHANGED.equals(intent.getAction()))) {
+                return;
             }
             onTimeChanged();
         }
@@ -642,12 +645,9 @@
      */
     @UnsupportedAppUsage
     private void onTimeChanged() {
-        // mShouldRunTicker always equals the last value passed into onVisibilityAggregated
-        if (mShouldRunTicker) {
-            mTime.setTimeInMillis(System.currentTimeMillis());
-            setText(DateFormat.format(mFormat, mTime));
-            setContentDescription(DateFormat.format(mDescFormat, mTime));
-        }
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        setText(DateFormat.format(mFormat, mTime));
+        setContentDescription(DateFormat.format(mDescFormat, mTime));
     }
 
     /** @hide */
diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
index 3fddfc8..04ad7e9 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -99,9 +99,13 @@
         }
         List<AppTarget> appTargets = new ArrayList<>();
         for (ResolvedComponentInfo target : targets) {
-            appTargets.add(new AppTarget.Builder(new AppTargetId(target.name.flattenToString()))
-                    .setTarget(target.name.getPackageName(), mUser)
-                    .setClassName(target.name.getClassName()).build());
+            appTargets.add(
+                    new AppTarget.Builder(
+                        new AppTargetId(target.name.flattenToString()),
+                            target.name.getPackageName(),
+                            mUser)
+                    .setClassName(target.name.getClassName())
+                    .build());
         }
         mAppPredictor.sortTargets(appTargets, Executors.newSingleThreadExecutor(),
                 sortedAppTargets -> {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 37678dd..5b917cc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3614,7 +3614,7 @@
     <!-- Message of notification shown when contaminant is detected on the USB port. [CHAR LIMIT=NONE] -->
     <string name="usb_contaminant_detected_message">USB port is automatically disabled. Tap to learn more.</string>
     <!-- Title of notification shown when contaminant is no longer detected on the USB port. [CHAR LIMIT=NONE] -->
-    <string name="usb_contaminant_not_detected_title">Safe to use USB port</string>
+    <string name="usb_contaminant_not_detected_title">OK to use USB port</string>
     <!-- Message of notification shown when contaminant is no longer detected on the USB port. [CHAR LIMIT=NONE] -->
     <string name="usb_contaminant_not_detected_message">Phone no longer detects liquid or debris.</string>
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e524216..ad99cce 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -314,6 +314,8 @@
         <permission name="android.permission.SET_WALLPAPER" />
         <permission name="android.permission.SET_WALLPAPER_COMPONENT" />
         <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+        <!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
+        <permission name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 297153d..32f2fc2 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1930,11 +1930,11 @@
         public float[] mTempPositions; // no need to copy
         @UnsupportedAppUsage
         public float[] mPositions;
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
+        @UnsupportedAppUsage(trackingBug = 124050917)
         public int mStrokeWidth = -1; // if >= 0 use stroking.
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
+        @UnsupportedAppUsage(trackingBug = 124050917)
         public float mStrokeDashWidth = 0.0f;
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
+        @UnsupportedAppUsage(trackingBug = 124050917)
         public float mStrokeDashGap = 0.0f;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public float mRadius = 0.0f; // use this if mRadiusArray is null
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index a8f313b..dc3041f 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -400,7 +400,7 @@
     /**
      * Indicates that the audio may be captured by any app.
      *
-     * For privacy, the following usages can not be recorded: VOICE_COMMUNICATION*,
+     * For privacy, the following usages cannot be recorded: VOICE_COMMUNICATION*,
      * USAGE_NOTIFICATION*, USAGE_ASSISTANCE* and USAGE_ASSISTANT.
      *
      * On {@link android.os.Build.VERSION_CODES#Q}, this means only {@link #USAGE_UNKNOWN},
@@ -413,11 +413,11 @@
     /**
      * Indicates that the audio may only be captured by system apps.
      *
-     * System apps can capture for many purposes like accessibility, user guidance...
+     * System apps can capture for many purposes like accessibility, live captions, user guidance...
      * but abide to the following restrictions:
-     *  - the audio can not leave the device
-     *  - the audio can not be passed to a third party app
-     *  - the audio can not be recorded at a higher quality then 16kHz 16bit mono
+     *  - the audio cannot leave the device
+     *  - the audio cannot be passed to a third party app
+     *  - the audio cannot be recorded at a higher quality than 16kHz 16bit mono
      *
      * See {@link Builder#setAllowedCapturePolicy}.
      */
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 2f03d26..a82c78f 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -91,6 +91,20 @@
      */
     public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1;
 
+    /**
+     * An audio mix behavior where the targeted audio is played unaffected but a copy is
+     * accessible for capture through {@link AudioRecord}.
+     *
+     * Only capture of playback is supported, not capture of capture.
+     * Use concurrent capture instead to capture what is captured by other apps.
+     *
+     * The captured audio is an approximation of the played audio.
+     * Effects and volume are not applied, and track are mixed with different delay then in the HAL.
+     * As a result, this API is not suitable for echo cancelling.
+     * @hide
+     */
+    public static final int ROUTE_FLAG_LOOP_BACK_RENDER = ROUTE_FLAG_LOOP_BACK | ROUTE_FLAG_RENDER;
+
     private static final int ROUTE_FLAG_SUPPORTED = ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK;
 
     // MIX_TYPE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
@@ -125,6 +139,15 @@
      */
     public static final int MIX_STATE_MIXING = 1;
 
+    /** Maximum sampling rate for privileged playback capture*/
+    private static final int PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE = 16000;
+
+    /** Maximum channel number for privileged playback capture*/
+    private static final int PRIVILEDGED_CAPTURE_MAX_CHANNEL_NUMBER = 1;
+
+    /** Maximum channel number for privileged playback capture*/
+    private static final int PRIVILEDGED_CAPTURE_MAX_BYTES_PER_SAMPLE = 2;
+
     /**
      * The current mixing state.
      * @return one of {@link #MIX_STATE_DISABLED}, {@link #MIX_STATE_IDLE},
@@ -140,7 +163,8 @@
         return mRouteFlags;
     }
 
-    AudioFormat getFormat() {
+    /** @hide */
+    public AudioFormat getFormat() {
         return mFormat;
     }
 
@@ -182,6 +206,31 @@
         return true;
     }
 
+    /** @return an error string if the format would not allow Privileged playbackCapture
+     *          null otherwise
+     * @hide */
+    public static String canBeUsedForPrivilegedCapture(AudioFormat format) {
+        int sampleRate = format.getSampleRate();
+        if (sampleRate > PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE || sampleRate <= 0) {
+            return "Privileged audio capture sample rate " + sampleRate
+                   + " can not be over " + PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE + "kHz";
+        }
+        int channelCount = format.getChannelCount();
+        if (channelCount > PRIVILEDGED_CAPTURE_MAX_CHANNEL_NUMBER || channelCount <= 0) {
+            return "Privileged audio capture channel count " + channelCount + " can not be over "
+                   + PRIVILEDGED_CAPTURE_MAX_CHANNEL_NUMBER;
+        }
+        int encoding = format.getEncoding();
+        if (!format.isPublicEncoding(encoding) || !format.isEncodingLinearPcm(encoding)) {
+            return "Privileged audio capture encoding " + encoding + "is not linear";
+        }
+        if (format.getBytesPerSample(encoding) > PRIVILEDGED_CAPTURE_MAX_BYTES_PER_SAMPLE) {
+            return "Privileged audio capture encoding " + encoding + " can not be over "
+                   + PRIVILEDGED_CAPTURE_MAX_BYTES_PER_SAMPLE + " bytes per sample";
+        }
+        return null;
+    }
+
     /** @hide */
     @Override
     public boolean equals(Object o) {
@@ -390,6 +439,12 @@
                     }
                 }
             }
+            if (mRule.allowPrivilegedPlaybackCapture()) {
+                String error = AudioMix.canBeUsedForPrivilegedCapture(mFormat);
+                if (error != null) {
+                    throw new IllegalArgumentException(error);
+                }
+            }
             return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
                     mDeviceAddress);
         }
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index ed2fdae..c4afd95 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -365,6 +365,10 @@
         /**
          * Set if the audio of app that opted out of audio playback capture should be captured.
          *
+         * Caller of this method with <code>true</code>, MUST abide to the restriction listed in
+         * {@link ALLOW_CAPTURE_BY_SYSTEM}, including but not limited to the captured audio
+         * can not leave the capturing app, and the quality is limited to 16k mono.
+         *
          * The permission {@link CAPTURE_AUDIO_OUTPUT} or {@link CAPTURE_MEDIA_OUTPUT} is needed
          * to ignore the opt-out.
          *
diff --git a/packages/CarSystemUI/res/drawable/notification_handle_bar.xml b/packages/CarSystemUI/res/drawable/notification_handle_bar.xml
new file mode 100644
index 0000000..5ed7499
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/notification_handle_bar.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<ripple
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@android:color/white">
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/clear_all_button_radius"/>
+            <solid android:color="@android:color/white"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml
index 5c915b8..55b0d87 100644
--- a/packages/CarSystemUI/res/layout/notification_center_activity.xml
+++ b/packages/CarSystemUI/res/layout/notification_center_activity.xml
@@ -23,24 +23,27 @@
     android:background="@color/notification_shade_background_color">
 
     <View
-         android:id="@+id/glass_pane"
-         android:layout_width="match_parent"
-         android:layout_height="match_parent"
-         app:layout_constraintTop_toTopOf="parent"
-         app:layout_constraintBottom_toBottomOf="parent"
-         app:layout_constraintStart_toStartOf="parent"
-         app:layout_constraintEnd_toEndOf="parent"
-         android:translationZ="2dp"
-        />
+        android:id="@+id/glass_pane"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:translationZ="2dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+    />
 
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/notifications"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:orientation="vertical"
-        app:layout_constraintTop_toTopOf="parent"
+        android:paddingStart="@dimen/notification_shade_list_padding_bottom"
         app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"/>
+        app:layout_constraintTop_toTopOf="parent"/>
+
+    <include layout="@layout/notification_handle_bar"/>
 
 </com.android.car.notification.CarNotificationView>
diff --git a/packages/CarSystemUI/res/layout/notification_handle_bar.xml b/packages/CarSystemUI/res/layout/notification_handle_bar.xml
new file mode 100644
index 0000000..99c3a02
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/notification_handle_bar.xml
@@ -0,0 +1,30 @@
+<?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.
+*/
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <View
+        android:id="@+id/handle_bar"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/notification_shade_handle_bar_height"
+        android:layout_marginBottom="@dimen/notification_shade_handle_bar_margin_bottom"
+        android:layout_marginEnd="@dimen/notification_shade_handle_bar_margin_start"
+        android:layout_marginStart="@dimen/notification_shade_handle_bar_margin_end"
+        android:layout_marginTop="@dimen/notification_shade_handle_bar_margin_top"
+        android:background="@drawable/notification_handle_bar"/>
+</merge>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index 83ec351..0d69fbb 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -34,7 +34,7 @@
     <drawable name="system_bar_background">@color/status_bar_background_color</drawable>
 
     <!-- The background color of the notification shade -->
-    <color name="notification_shade_background_color">#99000000</color>
+    <color name="notification_shade_background_color">#DD000000</color>
 
     <!-- The color of the dividing line between grouped notifications. -->
     <color name="notification_divider_color">@*android:color/notification_action_list</color>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 8789c8a..0358357b 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -88,4 +88,14 @@
     <dimen name="car_volume_item_divider_width">1dp</dimen>
     <dimen name="car_volume_item_divider_margin_end">@*android:dimen/car_padding_4</dimen>
     <dimen name="car_volume_item_corner_radius">@*android:dimen/car_radius_3</dimen>
+
+    <!-- Car notification shade-->
+    <dimen name="notification_shade_handle_bar_height">10dp</dimen>
+    <dimen name="notification_shade_handle_bar_radius">20dp</dimen>
+    <dimen name="notification_shade_handle_bar_margin_start">500dp</dimen>
+    <dimen name="notification_shade_handle_bar_margin_end">500dp</dimen>
+    <dimen name="notification_shade_handle_bar_margin_top">20dp</dimen>
+    <dimen name="notification_shade_handle_bar_margin_bottom">10dp</dimen>
+    <dimen name="notification_shade_list_padding_bottom">0dp</dimen>
+
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 9b6ab06..54e468ee 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -131,6 +131,8 @@
     // The container for the notifications.
     private CarNotificationView mNotificationView;
     private RecyclerView mNotificationList;
+    // The handler bar view at the bottom of notification shade.
+    private View mHandleBar;
     // The controller for the notification view.
     private NotificationViewController mNotificationViewController;
     // The state of if the notification list is currently showing the bottom.
@@ -464,6 +466,7 @@
 
         mNotificationView = mStatusBarWindow.findViewById(R.id.notification_view);
         View glassPane = mStatusBarWindow.findViewById(R.id.glass_pane);
+        mHandleBar = mStatusBarWindow.findViewById(R.id.handle_bar);
         mNotificationView.setClickHandlerFactory(mNotificationClickHandlerFactory);
         mNotificationView.setNotificationDataManager(mNotificationDataManager);
 
@@ -521,7 +524,7 @@
 
                 boolean handled = closeGestureDetector.onTouchEvent(event);
                 boolean isTracking = mIsTracking;
-                Rect rect = mNotificationList.getClipBounds();
+                Rect rect = mNotificationView.getClipBounds();
                 float clippedHeight = 0;
                 if (rect != null) {
                     clippedHeight = rect.bottom;
@@ -609,7 +612,7 @@
             to = mNotificationView.getHeight();
         }
 
-        Rect rect = mNotificationList.getClipBounds();
+        Rect rect = mNotificationView.getClipBounds();
         if (rect != null) {
             float from = rect.bottom;
             animate(from, to, velocity, isClosing);
@@ -653,7 +656,7 @@
                 if (isClosing) {
                     mStatusBarWindowController.setPanelVisible(false);
                     mNotificationView.setVisibility(View.INVISIBLE);
-                    mNotificationList.setClipBounds(null);
+                    mNotificationView.setClipBounds(null);
                     mNotificationViewController.setIsInForeground(false);
                     // let the status bar know that the panel is closed
                     setPanelExpanded(false);
@@ -1012,8 +1015,12 @@
         Rect clipBounds = new Rect();
         clipBounds.set(0, 0, mNotificationView.getWidth(), height);
         // Sets the clip region on the notification list view.
-        mNotificationList.setClipBounds(clipBounds);
-
+        mNotificationView.setClipBounds(clipBounds);
+        if (mHandleBar != null) {
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams();
+            mHandleBar.setTranslationY(height - mHandleBar.getHeight() - lp.bottomMargin);
+        }
         if (mNotificationView.getHeight() > 0) {
             // Calculates the alpha value for the background based on how much of the notification
             // shade is visible to the user. When the notification shade is completely open then
@@ -1095,9 +1102,6 @@
         @Override
         public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
                 float distanceY) {
-            if (!mNotificationListAtBottomAtTimeOfTouch && !mNotificationListAtBottom) {
-                return false;
-            }
             // should not clip while scroll to the bottom of the list.
             if (!mNotificationListAtBottomAtTimeOfTouch) {
                 return false;
@@ -1134,7 +1138,8 @@
         @Override
         public boolean onFling(MotionEvent event1, MotionEvent event2,
                 float velocityX, float velocityY) {
-            if (!mNotificationListAtBottomAtTimeOfTouch && !mNotificationListAtBottom) {
+            // should not fling if the touch does not start when view is at the bottom of the list.
+            if (!mNotificationListAtBottomAtTimeOfTouch) {
                 return false;
             }
             if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
index ea7b378..06c5294 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
@@ -22,8 +22,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.image.DynamicSystemClient;
+import android.os.image.DynamicSystemManager;
 import android.util.FeatureFlagUtils;
-import android.util.Log;
 
 
 /**
@@ -37,21 +37,26 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (!featureFlagEnabled()) {
+        String action = intent.getAction();
+
+        if (!Intent.ACTION_BOOT_COMPLETED.equals(action)) {
             return;
         }
 
-        String action = intent.getAction();
+        DynamicSystemManager dynSystem =
+                (DynamicSystemManager) context.getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
 
-        Log.d(TAG, "Broadcast received: " + action);
+        boolean isInUse = (dynSystem != null) && dynSystem.isInUse();
 
-        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-            Intent startServiceIntent = new Intent(
-                    context, DynamicSystemInstallationService.class);
-
-            startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
-            context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
+        if (!isInUse && !featureFlagEnabled()) {
+            return;
         }
+
+        Intent startServiceIntent = new Intent(
+                context, DynamicSystemInstallationService.class);
+
+        startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
+        context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
     }
 
     private boolean featureFlagEnabled() {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index b0e28a0..077f7ec 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -37,7 +37,7 @@
 
     private static final String TAG = "InstallationAsyncTask";
 
-    private static final int READ_BUFFER_SIZE = 1 << 19;
+    private static final int READ_BUFFER_SIZE = 1 << 13;
 
     private class InvalidImageUrlException extends RuntimeException {
         private InvalidImageUrlException(String message) {
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
index 765e9f9..670b419 100644
--- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
@@ -39,9 +39,9 @@
     // TODO: Add build dependency on NetworkStack stable AIDL so we can stop hard coding class name
     private static final String NETWORK_STACK_CONNECTOR_CLASS =
             "android.net.INetworkStackConnector";
-    private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS =
+    public static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS =
             "watchdog_request_timeout_millis";
-    private static final long DEFAULT_REQUEST_TIMEOUT_MILLIS =
+    public static final long DEFAULT_REQUEST_TIMEOUT_MILLIS =
             TimeUnit.HOURS.toMillis(1);
     // Modified only #onCreate, using concurrent collection to ensure thread visibility
     private final Map<String, ExplicitHealthChecker> mSupportedCheckers = new ConcurrentHashMap<>();
diff --git a/packages/ExtServices/tests/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImplTest.java b/packages/ExtServices/tests/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImplTest.java
new file mode 100644
index 0000000..a9cb63e
--- /dev/null
+++ b/packages/ExtServices/tests/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImplTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ext.services.watchdog;
+
+import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_REQUESTED_PACKAGES;
+import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_SUPPORTED_PACKAGES;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteCallback;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.IExplicitHealthCheckService;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Contains the base tests that does not rely on the specific algorithm implementation.
+ */
+public class ExplicitHealthCheckServiceImplTest {
+    private static final String NETWORK_STACK_CONNECTOR_CLASS =
+            "android.net.INetworkStackConnector";
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+    private IExplicitHealthCheckService mService;
+    private String mNetworkStackPackageName;
+
+    @Rule
+    public ServiceTestRule mServiceTestRule;
+
+    @Before
+    public void setUp() throws Exception {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(
+                        Manifest.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE);
+
+        mServiceTestRule = new ServiceTestRule();
+        mService = IExplicitHealthCheckService.Stub.asInterface(
+                mServiceTestRule.bindService(getExtServiceIntent()));
+        mNetworkStackPackageName = getNetworkStackPackage();
+        assumeFalse(mNetworkStackPackageName == null);
+    }
+
+    @After
+    public void tearDown() {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testHealthCheckSupportedPackage() throws Exception {
+        List<PackageConfig> supportedPackages = new ArrayList<>();
+        CountDownLatch latch = new CountDownLatch(1);
+
+        mService.getSupportedPackages(new RemoteCallback(result -> {
+            supportedPackages.addAll(result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES));
+            latch.countDown();
+        }));
+        latch.await();
+
+        // TODO: Support DeviceConfig changes for the health check timeout
+        assertThat(supportedPackages).hasSize(1);
+        assertThat(supportedPackages.get(0).getPackageName())
+                .isEqualTo(mNetworkStackPackageName);
+        assertThat(supportedPackages.get(0).getHealthCheckTimeoutMillis())
+                .isEqualTo(ExplicitHealthCheckServiceImpl.DEFAULT_REQUEST_TIMEOUT_MILLIS);
+    }
+
+    @Test
+    public void testHealthCheckRequests() throws Exception {
+        List<String> requestedPackages = new ArrayList<>();
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        CountDownLatch latch3 = new CountDownLatch(1);
+
+        // Initially, no health checks requested
+        mService.getRequestedPackages(new RemoteCallback(result -> {
+            requestedPackages.addAll(result.getParcelableArrayList(EXTRA_REQUESTED_PACKAGES));
+            latch1.countDown();
+        }));
+
+        // Verify that no health checks requested
+        latch1.await();
+        assertThat(requestedPackages).isEmpty();
+
+        // Then request health check
+        mService.request(mNetworkStackPackageName);
+
+        // Verify that health check is requested for network stack
+        mService.getRequestedPackages(new RemoteCallback(result -> {
+            requestedPackages.addAll(result.getParcelableArrayList(EXTRA_REQUESTED_PACKAGES));
+            latch2.countDown();
+        }));
+        latch2.await();
+        assertThat(requestedPackages).hasSize(1);
+        assertThat(requestedPackages.get(0)).isEqualTo(mNetworkStackPackageName);
+
+        // Then cancel health check
+        requestedPackages.clear();
+        mService.cancel(mNetworkStackPackageName);
+
+        // Verify that health check is cancelled for network stack
+        mService.getRequestedPackages(new RemoteCallback(result -> {
+            requestedPackages.addAll(result.getParcelableArrayList(EXTRA_REQUESTED_PACKAGES));
+            latch3.countDown();
+        }));
+        latch3.await();
+        assertThat(requestedPackages).isEmpty();
+    }
+
+    private String getNetworkStackPackage() {
+        Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        if (comp != null) {
+            return comp.getPackageName();
+        } else {
+            // On Go devices, or any device that does not ship the network stack module.
+            // The network stack will live in system_server process, so no need to monitor.
+            return null;
+        }
+    }
+
+    private Intent getExtServiceIntent() {
+        ComponentName component = getExtServiceComponentNameLocked();
+        if (component == null) {
+            fail("Health check service not found");
+        }
+        Intent intent = new Intent();
+        intent.setComponent(component);
+        return intent;
+    }
+
+    private ComponentName getExtServiceComponentNameLocked() {
+        ServiceInfo serviceInfo = getExtServiceInfoLocked();
+        if (serviceInfo == null) {
+            return null;
+        }
+
+        final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+        if (!Manifest.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE
+                .equals(serviceInfo.permission)) {
+            return null;
+        }
+        return name;
+    }
+
+    private ServiceInfo getExtServiceInfoLocked() {
+        final String packageName =
+                mContext.getPackageManager().getServicesSystemSharedLibraryPackageName();
+        if (packageName == null) {
+            return null;
+        }
+
+        final Intent intent = new Intent(ExplicitHealthCheckService.SERVICE_INTERFACE);
+        intent.setPackage(packageName);
+        final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            return null;
+        }
+        return resolveInfo.serviceInfo;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
index 786139f..b2e75ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
@@ -77,5 +77,17 @@
             Settings.Global.putLong(resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
                     System.currentTimeMillis())
         }
+
+        /**
+         * Returns when the estimate was last updated as an Instant
+         */
+        @JvmStatic
+        fun getLastCacheUpdateTime(context: Context): Instant {
+            return Instant.ofEpochMilli(
+                    Settings.Global.getLong(
+                            context.contentResolver,
+                            Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
+                            -1))
+        }
     }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0fa4155..aba88ab 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -198,6 +198,9 @@
     <!-- Permission required to test ContentResolver caching. -->
     <uses-permission android:name="android.permission.CACHE_CONTENT" />
 
+    <!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
+    <uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml
deleted file mode 100644
index c471b3830..0000000
--- a/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="40dp"
-        android:height="40dp"
-        android:viewportWidth="40"
-        android:viewportHeight="40">
-    <path
-        android:fillColor="#9AA0A6"
-        android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7266L16.2734 24.6666L20 20.94L23.7267 24.6666L24.6667 23.7266L20.94 20L24.6667 16.2733Z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
index 15f14d8..8b34080 100644
--- a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
+++ b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
@@ -20,6 +20,6 @@
     android:viewportWidth="40"
     android:viewportHeight="40">
     <path
-        android:fillColor="#5F6368"
+        android:fillColor="@color/notification_section_clear_all_btn_color"
         android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/>
 </vector>
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index 5b93edd..db40c4f 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -30,11 +30,12 @@
     <com.android.systemui.statusbar.AlphaOptimizedButton
         style="@android:style/Widget.Material.Button.Borderless"
         android:id="@+id/settings_button"
-        android:layout_gravity="end"
+        android:layout_gravity="start"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:focusable="true"
         android:text="@string/manage_bubbles_text"
-        android:textColor="?attr/wallpaperTextColor"/>
+        android:textColor="?attr/wallpaperTextColor"
+    />
 
 </com.android.systemui.bubbles.BubbleExpandedView>
diff --git a/packages/SystemUI/res/layout/contaminant_dialog.xml b/packages/SystemUI/res/layout/contaminant_dialog.xml
new file mode 100644
index 0000000..ea6d900
--- /dev/null
+++ b/packages/SystemUI/res/layout/contaminant_dialog.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** 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:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="18dp"
+        android:paddingBottom="18dp"
+        android:textAlignment="center"
+        android:fontFamily="google-sans-medium"
+        android:textSize="20sp"
+        android:textStyle="bold"
+        android:textColor="?android:attr/textColorPrimary"/>
+
+    <TextView
+        android:id="@+id/message"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="24dp"
+        android:paddingRight="24dp"
+        android:paddingBottom="24dp"
+        android:textAlignment="center"
+        android:textSize="16sp"
+        android:fontFamily="roboto-regular"
+        android:textColor="?android:attr/textColorPrimary" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="8dp"
+        android:focusable="true">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="2dp"
+            android:background="@android:drawable/divider_horizontal_bright" />
+
+        <TextView
+            android:id="@+id/learnMore"
+            style="@style/USBContaminant.UserAction" />
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="2dp"
+            android:background="@android:drawable/divider_horizontal_bright" />
+
+        <TextView
+            android:id="@+id/enableUsb"
+            style="@style/USBContaminant.UserAction" />
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="2dp"
+            android:background="@android:drawable/divider_horizontal_bright" />
+
+        <TextView
+          android:id="@+id/gotIt"
+          style="@style/USBContaminant.UserAction" />
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 087e0bd..4b672ee0 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -228,7 +228,7 @@
                 android:focusable="true">
                 <ImageView
                     android:id="@+id/alert_icon"
-                    android:src="@drawable/ic_notification_interruptive"
+                    android:src="@drawable/ic_notifications_alert"
                     android:background="@android:color/transparent"
                     android:layout_gravity="center"
                     android:layout_width="wrap_content"
@@ -249,6 +249,7 @@
                     android:text="@string/notification_alert_title"/>
                 <TextView
                     android:id="@+id/alert_summary"
+                    android:visibility="gone"
                     android:paddingTop="@dimen/notification_importance_button_padding"
                     android:text="@string/notification_channel_summary_default"
                     android:layout_width="match_parent"
@@ -271,7 +272,7 @@
                 android:focusable="true">
                 <ImageView
                     android:id="@+id/silence_icon"
-                    android:src="@drawable/ic_notification_gentle"
+                    android:src="@drawable/ic_notifications_silence"
                     android:background="@android:color/transparent"
                     android:layout_gravity="center"
                     android:layout_width="wrap_content"
@@ -292,6 +293,7 @@
                     android:text="@string/notification_silence_title"/>
                 <TextView
                     android:id="@+id/silence_summary"
+                    android:visibility="gone"
                     android:paddingTop="@dimen/notification_importance_button_padding"
                     android:text="@string/notification_channel_summary_default"
                     android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index d0783a0..3582d39 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/header_text_container"
     android:layout_width="match_parent"
     android:layout_height="@dimen/qs_header_tooltip_height"
@@ -23,19 +23,12 @@
     android:paddingEnd="@dimen/status_bar_padding_end"
     android:theme="@style/QSHeaderTheme">
 
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_gravity="start|center_vertical"
-        android:gravity="center_vertical">
-
-        <LinearLayout
+        <com.android.systemui.qs.QSHeaderInfoLayout
             android:id="@+id/status_container"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_gravity="start|center_vertical"
+            android:layout_width="match_parent"
             android:layout_weight="1"
-            android:gravity="center_vertical" >
+            android:layout_height="match_parent"
+            android:gravity="start" >
 
             <LinearLayout
                 android:id = "@+id/alarm_container"
@@ -98,21 +91,14 @@
                     android:textAppearance="@style/TextAppearance.QS.Status"
                     android:visibility="gone"/>
             </LinearLayout>
-        </LinearLayout>
-
-        <View
-            android:minWidth="@dimen/qs_status_separator"
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1"/>
-
+        </com.android.systemui.qs.QSHeaderInfoLayout>
 
         <include layout="@layout/qs_carrier_group"
                  android:id="@+id/carrier_group"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"
+                 android:layout_marginStart="@dimen/qs_status_separator"
                  android:layout_gravity="end|center_vertical"
                  android:focusable="false"/>
-    </LinearLayout>
 
-</FrameLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index 2b21006..0c3c597 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -43,7 +43,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:layout_marginLeft="@dimen/notification_section_header_padding_left"
+            android:layout_marginStart="@dimen/notification_section_header_padding_left"
             android:text="@string/notification_section_header_gentle"
             android:textSize="12sp"
             android:textColor="@color/notification_section_header_label_color"
@@ -52,9 +52,10 @@
             android:id="@+id/btn_clear_all"
             android:layout_width="@dimen/notification_section_header_height"
             android:layout_height="@dimen/notification_section_header_height"
-            android:layout_marginRight="4dp"
+            android:layout_marginEnd="4dp"
             android:src="@drawable/status_bar_notification_section_header_clear_btn"
             android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
+            android:scaleType="center"
             />
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index e25faa2..addc10a 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -50,6 +50,7 @@
     <color name="notification_guts_button_color">@color/GM2_blue_200</color>
 
     <color name="notification_section_header_label_color">@color/GM2_grey_200</color>
+    <color name="notification_section_clear_all_btn_color">@color/GM2_grey_500</color>
     <color name="notification_channel_dialog_separator">@color/GM2_grey_700</color>
 
     <!-- The color of the background in the top part of QSCustomizer -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 6d7e205..490473ce 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -98,6 +98,7 @@
     <color name="notification_guts_button_color">@color/GM2_blue_700</color>
 
     <color name="notification_section_header_label_color">@color/GM2_grey_900</color>
+    <color name="notification_section_clear_all_btn_color">@color/GM2_grey_700</color>
     <!-- The divider view for the notification channel editor half-shelf -->
     <color name="notification_channel_dialog_separator">@color/GM2_grey_200</color>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b49b612..fb226c7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -701,7 +701,7 @@
     <!-- The top padding of the clear all button -->
     <dimen name="clear_all_padding_top">12dp</dimen>
 
-    <dimen name="notification_section_header_height">40dp</dimen>
+    <dimen name="notification_section_header_height">48dp</dimen>
     <dimen name="notification_section_header_padding_left">16dp</dimen>
 
     <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c95dbfe..9831250 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -166,7 +166,7 @@
     <string name="usb_contaminant_title">USB port disabled</string>
 
     <!-- Message of USB contaminant presence dialog [CHAR LIMIT=NONE] -->
-    <string name="usb_contaminant_message">To protect your device from liquid or debris, the USB port is disabled and won\u2019t detect any accessories.\n\nYou\u2019ll be notified when it\u2019s safe to use the USB port again.</string>
+    <string name="usb_contaminant_message">To protect your device from liquid or debris, the USB port is disabled and won\u2019t detect any accessories.\n\nYou\u2019ll be notified when it\u2019s okay to use the USB port again.</string>
 
     <!-- Toast for enabling ports from USB contaminant dialog [CHAR LIMIT=NONE] -->
     <string name="usb_port_enabled">USB port enabled to detect chargers and accessories</string>
@@ -174,6 +174,9 @@
     <!-- Button text to disable contaminant detection [CHAR LIMIT=NONE] -->
     <string name="usb_disable_contaminant_detection">Enable USB</string>
 
+    <!-- Button text to disable contaminant detection [CHAR LIMIT=NONE] -->
+    <string name="learn_more">Learn more</string>
+
     <!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
          on a phone).  [CHAR LIMIT=25] -->
     <string name="compat_mode_on">Zoom to fill screen</string>
@@ -1118,10 +1121,10 @@
     <string name="manage_notifications_text">Manage</string>
 
     <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
-    <string name="notification_section_header_gentle">Gentle notifications</string>
+    <string name="notification_section_header_gentle">Silent notifications</string>
 
     <!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] -->
-    <string name="accessibility_notification_section_header_gentle_clear_all">Clear all gentle notifications</string>
+    <string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string>
 
     <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
     <string name="dnd_suppressing_shade_text">Notifications paused by Do Not Disturb</string>
@@ -1656,13 +1659,13 @@
     <string name="inline_minimize_button">Minimize</string>
 
     <!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] -->
-    <string name="inline_silent_button_silent">Gentle</string>
+    <string name="inline_silent_button_silent">Silent</string>
 
     <!-- Notification inline controls: button to continue showing notifications silently [CHAR_LIMIT=35] -->
     <string name="inline_silent_button_stay_silent">Stay silent</string>
 
     <!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] -->
-    <string name="inline_silent_button_alert">Interruptive</string>
+    <string name="inline_silent_button_alert">Alerting</string>
 
     <!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] -->
     <string name="inline_silent_button_keep_alerting">Keep alerting</string>
@@ -2375,7 +2378,7 @@
     <string name="auto_saver_title">Tap to schedule Battery Saver</string>
 
     <!-- The content of the notification to suggest enabling automatic battery saver.  [CHAR LIMIT=NONE]-->
-    <string name="auto_saver_text">Turn on automatically when battery is at <xliff:g id="percentage">%d</xliff:g>%%</string>
+    <string name="auto_saver_text">Turn on when battery is likely to run out</string>
 
     <!-- An action on the notification to suggest enabling automatic battery saver: Do not turn on automatic battery saver.  [CHAR LIMIT=NONE]-->
     <string name="no_auto_saver_action">No thanks</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 59ed5ce..04cd30c 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -572,4 +572,22 @@
         <item name="android:backgroundDimEnabled">true</item>
         <item name="android:windowCloseOnTouchOutside">true</item>
     </style>
+
+    <!-- USB Contaminant dialog -->
+    <style name ="USBContaminant" />
+
+    <style name ="USBContaminant.UserAction">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:fontFamily">roboto-regular</item>
+        <item name="android:paddingLeft">16dp</item>
+        <item name="android:paddingTop">16dp</item>
+        <item name="android:paddingRight">24dp</item>
+        <item name="android:paddingBottom">16dp</item>
+        <item name="android:textAlignment">viewStart</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:clickable">true</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index b826b30..77bb514 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -73,6 +73,12 @@
     void onAssistantProgress(float progress) = 12;
 
     /**
+    * Proxies the assistant gesture fling velocity (in pixels per millisecond) upon completion.
+    * Velocity is 0 for drag gestures.
+    */
+    void onAssistantGestureCompletion(float velocity) = 18;
+
+    /**
      * Start the assistant.
      */
     void startAssistant(in Bundle bundle) = 13;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index a3b2c95..51bd9f8 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -203,6 +203,14 @@
         // intentional no-op, vendor's AssistManager implementation should override if needed.
     }
 
+    /** Called when the user has invoked the assistant with the incoming velocity, in pixels per
+     * millisecond. For invocations without a velocity (e.g. slow drag), the velocity is set to
+     * zero.
+     */
+    public void onAssistantGestureCompletion(float velocity) {
+        // intentional no-op, vendor's AssistManager implementation should override if needed.
+    }
+
     public void hideAssist() {
         mAssistUtils.hideCurrentSession();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 3b652b7..e7948b5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -174,8 +174,9 @@
 
 
         mPointerDrawable = new ShapeDrawable(TriangleShape.create(
-                mPointerWidth, mPointerHeight, false /* pointUp */));
+                mPointerWidth, mPointerHeight, true /* pointUp */));
         mPointerView.setBackground(mPointerDrawable);
+        mPointerView.setVisibility(GONE);
 
         mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
                 R.dimen.bubble_expanded_header_height);
@@ -186,8 +187,14 @@
                 true /* singleTaskInstance */);
         addView(mActivityView);
 
-        // Make sure pointer is below activity view
-        bringChildToFront(mPointerView);
+        // Expanded stack layout, top to bottom:
+        // Expanded view container
+        // ==> bubble row
+        // ==> expanded view
+        //   ==> activity view
+        //   ==> manage button
+        bringChildToFront(mActivityView);
+        bringChildToFront(mSettingsIcon);
 
         applyThemeAttrs();
 
@@ -444,6 +451,7 @@
         // Adjust for the pointer size
         x -= (mPointerView.getWidth() / 2f);
         mPointerView.setTranslationX(x);
+        mPointerView.setVisibility(VISIBLE);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 50419b9..bec90d2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -176,6 +176,7 @@
     private int mExpandedViewPadding;
     private int mExpandedAnimateXDistance;
     private int mExpandedAnimateYDistance;
+    private int mPointerHeight;
     private int mStatusBarHeight;
     private int mPipDismissHeight;
     private int mImeOffset;
@@ -303,6 +304,8 @@
                 res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance);
         mExpandedAnimateYDistance =
                 res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
+        mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
+
         mStatusBarHeight =
                 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
         mPipDismissHeight = mContext.getResources().getDimensionPixelSize(
@@ -1282,15 +1285,16 @@
      */
     int getMaxExpandedHeight() {
         int expandedY = (int) mExpandedAnimationController.getExpandedY();
-        return expandedY - getStatusBarHeight();
+        // PIP dismiss view uses FLAG_LAYOUT_IN_SCREEN so we need to subtract the bottom inset
+        int pipDismissHeight = mPipDismissHeight - getBottomInset();
+        return mDisplaySize.y - expandedY - mBubbleSize - pipDismissHeight;
     }
 
     /**
      * Calculates the y position of the expanded view when it is expanded.
      */
     float getYPositionForExpandedView() {
-        return mExpandedAnimationController.getExpandedY()
-                - mExpandedBubble.expandedView.getExpandedSize() - mBubblePadding;
+        return getStatusBarHeight() + mBubbleSize + mBubblePadding + mPointerHeight;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 4674a1f..ae8043f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -301,13 +301,11 @@
             return 0;
         }
         final WindowInsets insets = mLayout.getRootWindowInsets();
-        int keyboardHeight = insets.getSystemWindowInsetBottom()
-                - insets.getStableInsetBottom();
-        float bottomInset = keyboardHeight > 0
-                ? keyboardHeight
-                : (mPipDismissHeight - insets.getStableInsetBottom());
-        // Stable insets are excluded from display size, so we must subtract it
-        return mDisplaySize.y - mBubbleSizePx - mBubblePaddingPx - bottomInset;
+        return mBubblePaddingPx + Math.max(
+            mStatusBarHeight,
+            insets.getDisplayCutout() != null
+                ? insets.getDisplayCutout().getSafeInsetTop()
+                : 0);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index f6cd199..4982dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -118,6 +118,8 @@
 
     private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING =
             "android.settings.BATTERY_SAVER_SETTINGS";
+    public static final String BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION =
+            "com.android.settings.BATTERY_SAVER_SCHEDULE_SETTINGS";
 
     private static final String BATTERY_SAVER_DESCRIPTION_URL_KEY = "url";
 
@@ -152,16 +154,18 @@
     private SystemUIDialog mThermalShutdownDialog;
     @VisibleForTesting SystemUIDialog mUsbHighTempDialog;
     private BatteryStateSnapshot mCurrentBatterySnapshot;
+    private ActivityStarter mActivityStarter;
 
     /**
      */
     @Inject
-    public PowerNotificationWarnings(Context context) {
+    public PowerNotificationWarnings(Context context, ActivityStarter activityStarter) {
         mContext = context;
         mNoMan = mContext.getSystemService(NotificationManager.class);
         mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mKeyguard = mContext.getSystemService(KeyguardManager.class);
         mReceiver.init();
+        mActivityStarter = activityStarter;
     }
 
     @Override
@@ -172,7 +176,6 @@
         pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
         pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null);
         pw.print("mSaverEnabledConfirmation=");
-        pw.println(mSaverEnabledConfirmation != null ? "not null" : null);
         pw.print("mHighTempWarning="); pw.println(mHighTempWarning);
         pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null);
         pw.print("mThermalShutdownDialog=");
@@ -305,8 +308,7 @@
                         .setWhen(0)
                         .setShowWhen(false)
                         .setContentTitle(mContext.getString(R.string.auto_saver_title))
-                        .setContentText(mContext.getString(R.string.auto_saver_text,
-                                getLowBatteryAutoTriggerDefaultLevel()));
+                        .setContentText(mContext.getString(R.string.auto_saver_text));
         nb.setContentIntent(pendingBroadcast(ACTION_ENABLE_AUTO_SAVER));
         nb.setDeleteIntent(pendingBroadcast(ACTION_DISMISS_AUTO_SAVER_SUGGESTION));
         nb.addAction(0,
@@ -673,51 +675,14 @@
         return builder;
     }
 
-    private void showAutoSaverEnabledConfirmation() {
-        if (mSaverEnabledConfirmation != null) return;
-
-        // Open the Battery Saver setting page.
-        final Intent actionBatterySaverSetting =
-                new Intent(SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        final SystemUIDialog d = new SystemUIDialog(mContext);
-        d.setTitle(R.string.auto_saver_enabled_title);
-        d.setMessage(mContext.getString(R.string.auto_saver_enabled_text,
-                getLowBatteryAutoTriggerDefaultLevel()));
-
-        // "Got it". Just close the dialog. Automatic battery has been enabled already.
-        d.setPositiveButton(R.string.auto_saver_okay_action,
-                (dialog, which) -> onAutoSaverEnabledConfirmationClosed());
-
-        // "Settings" -> Opens the battery saver settings activity.
-        d.setNeutralButton(R.string.open_saver_setting_action, (dialog, which) -> {
-            mContext.startActivity(actionBatterySaverSetting);
-            onAutoSaverEnabledConfirmationClosed();
-        });
-        d.setShowForAllUsers(true);
-        d.setOnDismissListener((dialog) -> onAutoSaverEnabledConfirmationClosed());
-        d.show();
-        mSaverEnabledConfirmation = d;
-    }
-
-    private void onAutoSaverEnabledConfirmationClosed() {
-        mSaverEnabledConfirmation = null;
-    }
-
     private void setSaverMode(boolean mode, boolean needFirstTimeWarning) {
         BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning);
     }
 
-    private void scheduleAutoBatterySaver() {
-        int autoTriggerThreshold = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        if (autoTriggerThreshold == 0) {
-            autoTriggerThreshold = 15;
-        }
-
-        BatterySaverUtils.ensureAutoBatterySaver(mContext, autoTriggerThreshold);
-        showAutoSaverEnabledConfirmation();
+    private void startBatterySaverSchedulePage() {
+        Intent intent = new Intent(BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mActivityStarter.startActivity(intent, true /* dismissShade */);
     }
 
     private final class Receiver extends BroadcastReceiver {
@@ -771,7 +736,7 @@
                 dismissAutoSaverSuggestion();
             } else if (ACTION_ENABLE_AUTO_SAVER.equals(action)) {
                 dismissAutoSaverSuggestion();
-                scheduleAutoBatterySaver();
+                startBatterySaverSchedulePage();
             } else if (ACTION_AUTO_SAVER_NO_THANKS.equals(action)) {
                 dismissAutoSaverSuggestion();
                 BatterySaverUtils.suppressAutoBatterySaver(context);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
new file mode 100644
index 0000000..86f54a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.qs
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.widget.FrameLayout
+import com.android.systemui.R
+
+/**
+ * Container for the Next Alarm and Ringer status texts in [QuickStatusBarHeader].
+ *
+ * If both elements are visible, it splits the available space according to the following rules:
+ * * If both views add up to less than the total space, they take all the space they need.
+ * * If both views are larger than half the space, each view takes half the space.
+ * * Otherwise, the smaller view takes the space it needs and the larger one takes all remaining
+ * space.
+ */
+class QSHeaderInfoLayout @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyle: Int = 0,
+        defStyleRes: Int = 0
+) : FrameLayout(context, attrs, defStyle, defStyleRes) {
+
+    private lateinit var alarmContainer: View
+    private lateinit var ringerContainer: View
+    private lateinit var statusSeparator: View
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        alarmContainer = findViewById(R.id.alarm_container)
+        ringerContainer = findViewById(R.id.ringer_container)
+        statusSeparator = findViewById(R.id.status_separator)
+    }
+
+    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+        // At most one view is there
+        if (statusSeparator.visibility == View.GONE) super.onLayout(changed, l, t, r, b)
+        else {
+            val alarmWidth = alarmContainer.measuredWidth
+            val separatorWidth = statusSeparator.measuredWidth
+            val ringerWidth = ringerContainer.measuredWidth
+            val availableSpace = (r - l) - separatorWidth
+            var left = l
+            if (alarmWidth < availableSpace / 2) {
+                alarmContainer.layout(left, t, left + alarmWidth, b)
+                left += alarmWidth
+                statusSeparator.layout(left, t, left + separatorWidth, b)
+                left += separatorWidth
+                ringerContainer.layout(left, t, left + Math.min(ringerWidth, r - left), b)
+            } else if (ringerWidth < availableSpace / 2) {
+                val alarmAllocation = Math.min(availableSpace - ringerWidth, alarmWidth)
+                alarmContainer.layout(left, t, left + alarmAllocation, b)
+                left += alarmWidth
+                statusSeparator.layout(left, t, left + separatorWidth, b)
+                left += separatorWidth
+                ringerContainer.layout(left, t, left + ringerWidth, b)
+            } else {
+                alarmContainer.layout(left, t, left + availableSpace / 2, b)
+                left += availableSpace / 2
+                statusSeparator.layout(left, t, left + separatorWidth, b)
+                ringerContainer.layout(r - availableSpace / 2, t, r, b)
+            }
+        }
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(
+                MeasureSpec.makeMeasureSpec(
+                        MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST),
+                heightMeasureSpec)
+        val width = MeasureSpec.getSize(widthMeasureSpec)
+        // Once we measure the views, using as much space as they need, we need to remeasure them
+        // assigning them their final width. This is because TextViews decide whether to MARQUEE
+        // after onMeasure.
+        if (statusSeparator.visibility != View.GONE) {
+            val alarmWidth = alarmContainer.measuredWidth
+            val separatorWidth = statusSeparator.measuredWidth
+            val ringerWidth = ringerContainer.measuredWidth
+            val availableSpace = MeasureSpec.getSize(width) - separatorWidth
+            if (alarmWidth < availableSpace / 2) {
+                measureChild(
+                        ringerContainer,
+                        MeasureSpec.makeMeasureSpec(
+                                Math.min(ringerWidth, availableSpace - alarmWidth),
+                                MeasureSpec.AT_MOST),
+                        heightMeasureSpec)
+            } else if (ringerWidth < availableSpace / 2) {
+                measureChild(alarmContainer,
+                        MeasureSpec.makeMeasureSpec(
+                                Math.min(alarmWidth, availableSpace - ringerWidth),
+                                MeasureSpec.AT_MOST),
+                        heightMeasureSpec)
+            } else {
+                measureChild(
+                        alarmContainer,
+                        MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST),
+                        heightMeasureSpec)
+                measureChild(
+                        ringerContainer,
+                        MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST),
+                        heightMeasureSpec)
+            }
+        }
+        setMeasuredDimension(width, measuredHeight)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index ce3c04e..9842748 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -321,6 +321,7 @@
         }
         mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
         mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
+        mRingerContainer.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
 
         return isOriginalVisible != ringerVisible ||
                 !Objects.equals(originalRingerText, mRingerModeTextView.getText());
@@ -337,6 +338,7 @@
         }
         mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
         mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
+        mNextAlarmContainer.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
 
         return isOriginalVisible != alarmVisible ||
                 !Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 51d259b..738f893 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -271,6 +271,19 @@
         }
 
         @Override
+        public void onAssistantGestureCompletion(float velocity) {
+            if (!verifyCaller("onAssistantGestureCompletion")) {
+                return;
+            }
+            long token = Binder.clearCallingIdentity();
+            try {
+                mHandler.post(() -> notifyAssistantGestureCompletion(velocity));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public void startAssistant(Bundle bundle) {
             if (!verifyCaller("startAssistant")) {
                 return;
@@ -684,6 +697,12 @@
         }
     }
 
+    private void notifyAssistantGestureCompletion(float velocity) {
+        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+            mConnectionCallbacks.get(i).onAssistantGestureCompletion(velocity);
+        }
+    }
+
     private void notifyStartAssistant(Bundle bundle) {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
             mConnectionCallbacks.get(i).startAssistant(bundle);
@@ -732,6 +751,7 @@
         default void onQuickScrubStarted() {}
         default void onBackButtonAlphaChanged(float alpha, boolean animate) {}
         default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
+        default void onAssistantGestureCompletion(float velocity) {}
         default void startAssistant(Bundle bundle) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 942f566..e4e8c80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -94,6 +94,8 @@
 
     private static final int BUTTON_ANIM_TIME_MS = 200;
 
+    private static final boolean SHOW_BUTTON_SUMMARY = false;
+
     private INotificationManager mINotificationManager;
     private PackageManager mPm;
     private MetricsLogger mMetricsLogger;
@@ -580,25 +582,27 @@
             transition.setDuration(BUTTON_ANIM_TIME_MS);
             TransitionManager.beginDelayedTransition(this, transition);
         }
-        if (blockState == ACTION_ALERT) {
-            TextView view = findViewById(R.id.alert_summary);
-            view.setVisibility(VISIBLE);
-            findViewById(R.id.silence_summary).setVisibility(GONE);
-            view.setText(R.string.notification_channel_summary_default);
-        } else {
-            TextView view = findViewById(R.id.silence_summary);
-            view.setVisibility(VISIBLE);
-            findViewById(R.id.alert_summary).setVisibility(GONE);
-            if (mShowInStatusBar) {
-                if (mShowOnLockscreen) {
-                    view.setText(R.string.notification_channel_summary_low_status_lock);
-                } else {
-                    view.setText(R.string.notification_channel_summary_low_status);
-                }
-            } else if (mShowOnLockscreen) {
-                view.setText(R.string.notification_channel_summary_low_lock);
+        if (SHOW_BUTTON_SUMMARY) {
+            if (blockState == ACTION_ALERT) {
+                TextView view = findViewById(R.id.alert_summary);
+                view.setVisibility(VISIBLE);
+                findViewById(R.id.silence_summary).setVisibility(GONE);
+                view.setText(R.string.notification_channel_summary_default);
             } else {
-                view.setText(R.string.notification_channel_summary_low);
+                TextView view = findViewById(R.id.silence_summary);
+                view.setVisibility(VISIBLE);
+                findViewById(R.id.alert_summary).setVisibility(GONE);
+                if (mShowInStatusBar) {
+                    if (mShowOnLockscreen) {
+                        view.setText(R.string.notification_channel_summary_low_status_lock);
+                    } else {
+                        view.setText(R.string.notification_channel_summary_low_status);
+                    }
+                } else if (mShowOnLockscreen) {
+                    view.setText(R.string.notification_channel_summary_low_lock);
+                } else {
+                    view.setText(R.string.notification_channel_summary_low);
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 82599f0..5747bb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -28,6 +28,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
@@ -40,18 +42,22 @@
 class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvider {
     private final NotificationStackScrollLayout mParent;
     private final ActivityStarter mActivityStarter;
+    private final StatusBarStateController mStatusBarStateController;
     private final boolean mUseMultipleSections;
 
     private SectionHeaderView mGentleHeader;
     private boolean mGentleHeaderVisible = false;
+    @Nullable private ExpandableNotificationRow mFirstGentleNotif;
     @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
 
     NotificationSectionsManager(
             NotificationStackScrollLayout parent,
             ActivityStarter activityStarter,
+            StatusBarStateController statusBarStateController,
             boolean useMultipleSections) {
         mParent = parent;
         mActivityStarter = activityStarter;
+        mStatusBarStateController = statusBarStateController;
         mUseMultipleSections = useMultipleSections;
     }
 
@@ -92,7 +98,7 @@
 
     @Override
     public boolean beginsSection(View view) {
-        return view == mGentleHeader;
+        return view == getFirstLowPriorityChild();
     }
 
     /**
@@ -104,6 +110,7 @@
             return;
         }
 
+        mFirstGentleNotif = null;
         int firstGentleNotifIndex = -1;
 
         final int n = mParent.getChildCount();
@@ -114,6 +121,7 @@
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
                 if (!row.getEntry().isHighPriority()) {
                     firstGentleNotifIndex = i;
+                    mFirstGentleNotif = row;
                     break;
                 }
             }
@@ -126,9 +134,12 @@
     }
 
     private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) {
+        final boolean showGentleHeader =
+                firstGentleNotifIndex != -1
+                        && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
         final int currentHeaderIndex = mParent.indexOfChild(mGentleHeader);
 
-        if (firstGentleNotifIndex == -1) {
+        if (!showGentleHeader) {
             if (mGentleHeaderVisible) {
                 mGentleHeaderVisible = false;
                 mParent.removeView(mGentleHeader);
@@ -208,7 +219,11 @@
 
     @Nullable
     private ActivatableNotificationView getFirstLowPriorityChild() {
-        return mGentleHeaderVisible ? mGentleHeader : null;
+        if (mGentleHeaderVisible) {
+            return mGentleHeader;
+        } else {
+            return mFirstGentleNotif;
+        }
     }
 
     @Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index de187f1..2651d4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -518,7 +518,8 @@
             NotificationRoundnessManager notificationRoundnessManager,
             AmbientPulseManager ambientPulseManager,
             DynamicPrivacyController dynamicPrivacyController,
-            ActivityStarter activityStarter) {
+            ActivityStarter activityStarter,
+            StatusBarStateController statusBarStateController) {
         super(context, attrs, 0, 0);
         Resources res = getResources();
 
@@ -534,6 +535,7 @@
                 new NotificationSectionsManager(
                         this,
                         activityStarter,
+                        statusBarStateController,
                         NotificationUtils.useNewInterruptionModel(context));
         mSectionsManager.inflateViews(context);
         mSectionsManager.setOnClearGentleNotifsClickListener(v -> {
@@ -913,7 +915,8 @@
             if (child.getVisibility() != View.GONE
                     && child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if ((row.isPinned() || row.isHeadsUpAnimatingAway()) && row.getTranslation() < 0) {
+                if ((row.isPinned() || row.isHeadsUpAnimatingAway()) && row.getTranslation() < 0
+                        && row.getProvider().shouldShowGutsOnSnapOpen()) {
                     top = Math.min(top, row.getTranslationY());
                     bottom = Math.max(bottom, row.getTranslationY() + row.getActualHeight());
                 }
@@ -4378,6 +4381,7 @@
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
         mAmbientState.setShadeExpanded(isExpanded);
         mStateAnimator.setShadeExpanded(isExpanded);
+        mSwipeHelper.setIsExpanded(isExpanded);
         if (changed) {
             if (!mIsExpanded) {
                 mGroupManager.collapseAllGroups();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 4569b66..0f711922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -48,6 +48,7 @@
     private static final long SWIPE_MENU_TIMING = 200;
 
     private NotificationMenuRowPlugin mCurrMenuRow;
+    private boolean mIsExpanded;
 
     public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback,
             Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
@@ -97,6 +98,10 @@
         return mFalsingCheck;
     }
 
+    public void setIsExpanded(boolean isExpanded) {
+        mIsExpanded = isExpanded;
+    }
+
     @Override
     protected void onChildSnappedBack(View animView, float targetLeft) {
         if (mCurrMenuRow != null && targetLeft == 0) {
@@ -200,7 +205,9 @@
         boolean slowSwipedFarEnough = swipedEnoughToShowMenu(menuRow) && isSlowSwipe;
         boolean isFastNonDismissGesture =
                 gestureFastEnough && !gestureTowardsMenu && !isDismissGesture;
-        boolean isMenuRevealingGestureAwayFromMenu = slowSwipedFarEnough || isFastNonDismissGesture;
+        boolean isAbleToShowMenu = menuRow.shouldShowGutsOnSnapOpen() || mIsExpanded;
+        boolean isMenuRevealingGestureAwayFromMenu = slowSwipedFarEnough
+                || (isFastNonDismissGesture && isAbleToShowMenu);
         int menuSnapTarget = menuRow.getMenuSnapTarget();
         boolean isNonFalseMenuRevealingGesture =
                 !isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
index ecf608b..aec14be 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
@@ -16,30 +16,33 @@
 
 package com.android.systemui.usb;
 
-import android.app.AlertDialog;
-import android.content.DialogInterface;
+import android.app.Activity;
 import android.content.Intent;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbManager;
 import android.hardware.usb.UsbPort;
 import android.os.Bundle;
 import android.util.Log;
+import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
 import com.android.systemui.R;
 
 /**
  * Activity that alerts the user when contaminant is detected on USB port.
  */
-public class UsbContaminantActivity extends AlertActivity
-                                  implements DialogInterface.OnClickListener {
+public class UsbContaminantActivity extends Activity implements View.OnClickListener {
     private static final String TAG = "UsbContaminantActivity";
 
     private UsbPort mUsbPort;
+    private TextView mLearnMore;
+    private TextView mGotIt;
+    private TextView mEnableUsb;
+    private TextView mTitle;
+    private TextView mMessage;
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -47,22 +50,30 @@
         window.addSystemFlags(WindowManager.LayoutParams
                 .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
 
         super.onCreate(icicle);
+        setContentView(R.layout.contaminant_dialog);
 
         Intent intent = getIntent();
         ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
         mUsbPort = port.getUsbPort(getSystemService(UsbManager.class));
 
-        final AlertController.AlertParams ap = mAlertParams;
-        ap.mTitle = getString(R.string.usb_contaminant_title);
-        ap.mMessage = getString(R.string.usb_contaminant_message);
-        ap.mNegativeButtonText = getString(android.R.string.ok);
-        ap.mNeutralButtonText = getString(R.string.usb_disable_contaminant_detection);
-        ap.mNegativeButtonListener = this;
-        ap.mNeutralButtonListener = this;
+        mLearnMore = findViewById(R.id.learnMore);
+        mEnableUsb = findViewById(R.id.enableUsb);
+        mGotIt = findViewById(R.id.gotIt);
+        mTitle = findViewById(R.id.title);
+        mMessage = findViewById(R.id.message);
 
-        setupAlert();
+        mTitle.setText(getString(R.string.usb_contaminant_title));
+        mMessage.setText(getString(R.string.usb_contaminant_message));
+        mEnableUsb.setText(getString(R.string.usb_disable_contaminant_detection));
+        mGotIt.setText(getString(R.string.got_it));
+        mLearnMore.setText(getString(R.string.learn_more));
+
+        mEnableUsb.setOnClickListener(this);
+        mGotIt.setOnClickListener(this);
+        mLearnMore.setOnClickListener(this);
     }
 
     @Override
@@ -71,8 +82,8 @@
     }
 
     @Override
-    public void onClick(DialogInterface dialog, int which) {
-        if (which == AlertDialog.BUTTON_NEUTRAL) {
+    public void onClick(View v) {
+        if (v == mEnableUsb) {
             try {
                 mUsbPort.enableContaminantDetection(false);
                 Toast.makeText(this, R.string.usb_port_enabled,
@@ -80,6 +91,13 @@
             } catch (Exception e) {
                 Log.e(TAG, "Unable to notify Usb service", e);
             }
+        } else if (v == mLearnMore) {
+            final Intent intent = new Intent();
+            intent.setClassName("com.android.settings",
+                    "com.android.settings.HelpTrampoline");
+            intent.putExtra(Intent.EXTRA_TEXT,
+                    "help_url_usb_contaminant_detected");
+            startActivity(intent);
         }
         finish();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 58c9311..afb63ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -37,6 +37,7 @@
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.util.NotificationChannels;
 
 import org.junit.Before;
@@ -57,7 +58,8 @@
     public void setUp() throws Exception {
         // Test Instance.
         mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
-        mPowerNotificationWarnings = new PowerNotificationWarnings(mContext);
+        ActivityStarter starter = mDependency.injectMockDependency(ActivityStarter.class);
+        mPowerNotificationWarnings = new PowerNotificationWarnings(mContext, starter);
         BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1,
                 BatteryManager.BATTERY_HEALTH_GOOD, 5, 15);
         mPowerNotificationWarnings.updateSnapshot(snapshot);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 67c4a92..b99958a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -38,6 +38,8 @@
 
 import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 import org.junit.Before;
@@ -57,17 +59,24 @@
 
     @Mock private NotificationStackScrollLayout mNssl;
     @Mock private ActivityStarterDelegate mActivityStarterDelegate;
+    @Mock private StatusBarStateController mStatusBarStateController;
 
     private NotificationSectionsManager mSectionsManager;
 
     @Before
     public void setUp() {
-        mSectionsManager = new NotificationSectionsManager(mNssl, mActivityStarterDelegate, true);
+        mSectionsManager =
+                new NotificationSectionsManager(
+                        mNssl,
+                        mActivityStarterDelegate,
+                        mStatusBarStateController,
+                        true);
         // Required in order for the header inflation to work properly
         when(mNssl.generateLayoutParams(any(AttributeSet.class)))
                 .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
         mSectionsManager.inflateViews(mContext);
         when(mNssl.indexOfChild(any(View.class))).thenReturn(-1);
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
     }
 
     @Test
@@ -185,6 +194,49 @@
         verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 1);
     }
 
+    @Test
+    public void testHeaderNotShownOnLockscreen() {
+        // GIVEN a stack of HI and LO notifs on the lockscreen
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+
+        // WHEN we update the section headers
+        mSectionsManager.updateSectionBoundaries();
+
+        // Then the section header is not added
+        verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt());
+    }
+
+    @Test
+    public void testHeaderShownWhenEnterLockscreen() {
+        // GIVEN a stack of HI and LO notifs on the lockscreen
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+        mSectionsManager.updateSectionBoundaries();
+
+        // WHEN we unlock
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+        mSectionsManager.updateSectionBoundaries();
+
+        // Then the section header is added
+        verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3);
+    }
+
+    @Test
+    public void testHeaderHiddenWhenEnterLockscreen() {
+        // GIVEN a stack of HI and LO notifs on the shade
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+        mSectionsManager.updateSectionBoundaries();
+
+        // WHEN we go back to the keyguard
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+        mSectionsManager.updateSectionBoundaries();
+
+        // Then the section header is removed
+        verify(mNssl).removeView(eq(mSectionsManager.getGentleHeaderView()));
+    }
+
     private enum ChildType { HEADER, HIPRI, LOPRI }
 
     private void setStackState(ChildType... children) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 09b8062..56265d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -153,7 +153,8 @@
                 true /* allowLongPress */, mNotificationRoundnessManager,
                 new AmbientPulseManager(mContext),
                 mock(DynamicPrivacyController.class),
-                mock(ActivityStarterDelegate.class));
+                mock(ActivityStarterDelegate.class),
+                mock(StatusBarStateController.class));
         mStackScroller = spy(mStackScrollerInternal);
         mStackScroller.setShelf(notificationShelf);
         mStackScroller.setStatusBar(mBar);
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 9d979a6..f92d0e0 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -152,7 +152,18 @@
 
     @Override
     public boolean isInUse() throws RemoteException {
-        return getGsiService().isGsiRunning();
+        boolean gsidWasRunning = "running".equals(SystemProperties.get("init.svc.gsid"));
+        boolean isInUse = false;
+
+        try {
+            isInUse = getGsiService().isGsiRunning();
+        } finally {
+            if (!gsidWasRunning && !isInUse) {
+                SystemProperties.set("ctl.stop", "gsid");
+            }
+        }
+
+        return isInUse;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index fc355b7..1fb29a6 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3580,7 +3580,7 @@
                 return Zygote.MOUNT_EXTERNAL_NONE;
             }
             if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
-                return Zygote.MOUNT_EXTERNAL_DEFAULT;
+                return Zygote.MOUNT_EXTERNAL_NONE;
             }
 
             // Determine if caller is holding runtime permission
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 1ce65561..ff6a537 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -45,7 +45,8 @@
 
     private static SystemServerInitThreadPool sInstance;
 
-    private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4,
+    private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(
+            Runtime.getRuntime().availableProcessors(),
             "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
 
     private List<String> mPendingTasks = new ArrayList<>();
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index a7fb99f..e097d85 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -617,9 +617,13 @@
             // deadlock and the watchdog as a whole to be ineffective)
             Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
                     public void run() {
-                        mActivity.addErrorToDropBox(
-                                "watchdog", null, "system_server", null, null, null,
-                                subject, null, stack, null);
+                        // If a watched thread hangs before init() is called, we don't have a
+                        // valid mActivity. So we can't log the error to dropbox.
+                        if (mActivity != null) {
+                            mActivity.addErrorToDropBox(
+                                    "watchdog", null, "system_server", null, null, null,
+                                    subject, null, stack, null);
+                        }
                         StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
                     }
                 };
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ea71a3b..a809d21 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -33,6 +33,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
 import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
@@ -18566,6 +18567,21 @@
         }
     }
 
+    /**
+     * Synchronously update the system ActivityThread, bypassing any deferred threading so any
+     * resources and overlaid values are available immediately.
+     */
+    public void updateSystemUiContext() {
+        PackageManagerInternal packageManagerInternal;
+        synchronized (this) {
+            packageManagerInternal = getPackageManagerInternalLocked();
+        }
+
+        ApplicationInfo ai = packageManagerInternal.getApplicationInfo("android",
+                GET_SHARED_LIBRARY_FILES, Binder.getCallingUid(), UserHandle.USER_SYSTEM);
+        ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai);
+    }
+
     void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
         final boolean updateFrameworkRes = packagesToUpdate.contains("android");
         if (updateFrameworkRes) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4cde931..86832f4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6698,7 +6698,10 @@
             boolean isVolumeController, IMediaProjection projection) {
         AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
 
-        if (!isPolicyRegisterAllowed(policyConfig, projection)) {
+        if (!isPolicyRegisterAllowed(policyConfig,
+                                     isFocusPolicy || isTestFocusPolicy || hasFocusListener,
+                                     isVolumeController,
+                                     projection)) {
             Slog.w(TAG, "Permission denied to register audio policy for pid "
                     + Binder.getCallingPid() + " / uid " + Binder.getCallingUid()
                     + ", need MODIFY_AUDIO_ROUTING or MediaProjection that can project audio");
@@ -6739,42 +6742,71 @@
      * as those policy do not modify the audio routing.
      */
     private boolean isPolicyRegisterAllowed(AudioPolicyConfig policyConfig,
-             IMediaProjection projection) {
+                                            boolean hasFocusAccess,
+                                            boolean isVolumeController,
+                                            IMediaProjection projection) {
 
-        boolean isLoopbackRenderPolicy = policyConfig.getMixes().stream().allMatch(
-                mix -> mix.getRouteFlags() == (mix.ROUTE_FLAG_RENDER | mix.ROUTE_FLAG_LOOP_BACK));
+        boolean requireValidProjection = false;
+        boolean requireCaptureAudioOrMediaOutputPerm = false;
+        boolean requireModifyRouting = false;
 
-        if (isLoopbackRenderPolicy) {
-            boolean allowPrivilegedPlaybackCapture = policyConfig.getMixes().stream().anyMatch(
-                    mix -> mix.getRule().allowPrivilegedPlaybackCapture());
-            if (allowPrivilegedPlaybackCapture
-                    && !(hasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
-                    || hasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT))) {
-                // Opt-out can not be bypassed without a system permission
-                return false;
+        if (hasFocusAccess || isVolumeController) {
+            requireModifyRouting |= true;
+        } else if (policyConfig.getMixes().isEmpty()) {
+            // An empty policy could be used to lock the focus or add mixes later
+            requireModifyRouting |= true;
+        }
+        for (AudioMix mix : policyConfig.getMixes()) {
+            // If mix is requesting a privileged capture
+            if (mix.getRule().allowPrivilegedPlaybackCapture()) {
+                // then it must have CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT permission
+                requireCaptureAudioOrMediaOutputPerm |= true;
+                // and its format must be low quality enough
+                String error = mix.canBeUsedForPrivilegedCapture(mix.getFormat());
+                if (error != null) {
+                    Log.e(TAG, error);
+                    return false;
+                }
             }
 
-            if (canProjectAudio(projection)) {
-                // Policy that do not modify the audio routing only need an audio projection
-                return true;
+            // If mix is RENDER|LOOPBACK, then an audio MediaProjection is enough
+            // otherwise MODIFY_AUDIO_ROUTING permission is required
+            if (mix.getRouteFlags() == mix.ROUTE_FLAG_LOOP_BACK_RENDER && projection != null) {
+                requireValidProjection |= true;
+            } else {
+                requireModifyRouting |= true;
             }
         }
 
-        boolean hasPermissionModifyAudioRouting =
-                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
-                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
-        if (hasPermissionModifyAudioRouting) {
-            return true;
+        if (requireCaptureAudioOrMediaOutputPerm
+                && !callerHasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT)
+                && !callerHasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)) {
+            Log.e(TAG, "Privileged audio capture requires CAPTURE_MEDIA_OUTPUT or "
+                      + "CAPTURE_AUDIO_OUTPUT system permission");
+            return false;
         }
-        return false;
+
+        if (requireValidProjection && !canProjectAudio(projection)) {
+            return false;
+        }
+
+        if (requireModifyRouting
+                && !callerHasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)) {
+            Log.e(TAG, "Can not capture audio without MODIFY_AUDIO_ROUTING");
+            return false;
+        }
+
+        return true;
     }
-    private boolean hasPermission(String permission) {
-        return PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(permission);
+
+    private boolean callerHasPermission(String permission) {
+        return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
     }
 
     /** @return true if projection is a valid MediaProjection that can project audio. */
     private boolean canProjectAudio(IMediaProjection projection) {
         if (projection == null) {
+            Log.e(TAG, "MediaProjection is null");
             return false;
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6d01375..99341d1 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -254,6 +254,9 @@
     // device).
     private Point mStableDisplaySize = new Point();
 
+    // Whether the system has finished booting or not.
+    private boolean mSystemReady;
+
     // The top inset of the default display.
     // This gets persisted so that the boot animation knows how to transition from the display's
     // full size to the size configured by the user. Right now we only persist and animate the top
@@ -330,6 +333,8 @@
         mCurrentUserId = UserHandle.USER_SYSTEM;
         ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
         mWideColorSpace = colorSpaces[1];
+
+        mSystemReady = false;
     }
 
     public void setupSchedulerPolicies() {
@@ -418,6 +423,10 @@
         synchronized (mSyncRoot) {
             mSafeMode = safeMode;
             mOnlyCore = onlyCore;
+            mSystemReady = true;
+            // Just in case the top inset changed before the system was ready. At this point, any
+            // relevant configuration should be in place.
+            recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
         }
 
         mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
@@ -1057,7 +1066,10 @@
     }
 
     private void recordTopInsetLocked(@Nullable LogicalDisplay d) {
-        if (d == null) {
+        // We must only persist the inset after boot has completed, otherwise we will end up
+        // overwriting the persisted value before the masking flag has been loaded from the
+        // resource overlay.
+        if (!mSystemReady || d == null) {
             return;
         }
         int topInset = d.getInsets().top;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index b2315c7..f28bce5 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -966,8 +966,9 @@
     }
 
     private void updateEnabled() {
-        // Generally follow location setting
-        boolean enabled = mContext.getSystemService(LocationManager.class).isLocationEnabled();
+        // Generally follow location setting for current user
+        boolean enabled = mContext.getSystemService(LocationManager.class)
+                .isLocationEnabledForUser(UserHandle.CURRENT);
 
         // ... but disable if PowerManager overrides
         enabled &= !mDisableGpsForPowerManager;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e42ed3b..4e1cac9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -36,6 +36,7 @@
 import android.content.res.Resources.Theme;
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
 import android.database.sqlite.SQLiteGlobal;
+import android.hardware.display.DisplayManagerInternal;
 import android.net.NetworkStackClient;
 import android.os.BaseBundle;
 import android.os.Binder;
@@ -790,6 +791,12 @@
         mSystemServiceManager.startService(new SensorPrivacyService(mSystemContext));
         traceEnd();
 
+        if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
+            // DisplayManager needs the overlay immediately.
+            mActivityManagerService.updateSystemUiContext();
+            LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
+        }
+
         // The sensor service needs access to package manager service, app ops
         // service, and permissions service, therefore we start it after them.
         // Start sensor service in a separate thread. Completion should be checked
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index 18e7530..9912ece 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -250,6 +250,8 @@
         out.writeInt(mStatus);
         out.writeString(mIcbNum);
         out.writeInt(mProvisionStatus);
+        out.writeInt(mClirInterrogationStatus);
+        out.writeInt(mClirOutgoingState);
     }
 
     @Override
@@ -273,6 +275,8 @@
         mStatus = in.readInt();
         mIcbNum = in.readString();
         mProvisionStatus = in.readInt();
+        mClirInterrogationStatus = in.readInt();
+        mClirOutgoingState = in.readInt();
     }
 
     public static final @android.annotation.NonNull Creator<ImsSsInfo> CREATOR =