Merge "Notify ImsService Status Correctly" into oc-dev
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4dea0e0..ad272b8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7445,7 +7445,7 @@
         final int offsetX = (anchorBounds != null)
                 ? anchorBounds.left - actualAnchorBounds.left : 0;
         int offsetY = (anchorBounds != null)
-                ? anchorBounds.bottom - actualAnchorBounds.bottom : 0;
+                ?  anchorBounds.top - actualAnchorBounds.top : 0;
 
         final boolean wasShowing;
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0041879..06509ae 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4257,15 +4257,17 @@
          * Construct a RemoteViews for the final notification header only. This will not be
          * colorized.
          *
+         * @param ambient if true, generate the header for the ambient display layout.
          * @hide
          */
-        public RemoteViews makeNotificationHeader() {
+        public RemoteViews makeNotificationHeader(boolean ambient) {
             Boolean colorized = (Boolean) mN.extras.get(EXTRA_COLORIZED);
             mN.extras.putBoolean(EXTRA_COLORIZED, false);
             RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
-                    R.layout.notification_template_header);
+                    ambient ? R.layout.notification_template_ambient_header
+                            : R.layout.notification_template_header);
             resetNotificationHeader(header);
-            bindNotificationHeader(header, false /* ambient */);
+            bindNotificationHeader(header, ambient);
             if (colorized != null) {
                 mN.extras.putBoolean(EXTRA_COLORIZED, colorized);
             } else {
@@ -4407,7 +4409,7 @@
                 }
             }
 
-            RemoteViews header = makeNotificationHeader();
+            RemoteViews header = makeNotificationHeader(false /* ambient */);
             header.setBoolean(R.id.notification_header, "setAcceptAllTouches", true);
             if (summary != null) {
                 mN.extras.putCharSequence(EXTRA_SUB_TEXT, summary);
diff --git a/core/java/android/service/vr/VrListenerService.java b/core/java/android/service/vr/VrListenerService.java
index c76d793..5da4560 100644
--- a/core/java/android/service/vr/VrListenerService.java
+++ b/core/java/android/service/vr/VrListenerService.java
@@ -110,7 +110,7 @@
      * transition.</p>
      *
      * @param component the {@link ComponentName} of the VR activity that the system has
-     *    switched to.
+     *    switched to, or null if the system is displaying a 2D activity in VR compatibility mode.
      *
      * @see android.app.Activity#setVrModeEnabled
      * @see android.R.attr#enableVrMode
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index bf0601d..13ebe5c 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -17,6 +17,8 @@
 package android.widget;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
@@ -26,6 +28,7 @@
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -62,7 +65,7 @@
  * <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> developer
  * guide.</p>
  * </div>
- */ 
+ */
 public class Toast {
     static final String TAG = "Toast";
     static final boolean localLOGV = false;
@@ -99,8 +102,16 @@
      *                 or {@link android.app.Activity} object.
      */
     public Toast(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Constructs an empty Toast object.  If looper is null, Looper.myLooper() is used.
+     * @hide
+     */
+    public Toast(@NonNull Context context, @Nullable Looper looper) {
         mContext = context;
-        mTN = new TN(context.getPackageName());
+        mTN = new TN(context.getPackageName(), looper);
         mTN.mY = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.toast_y_offset);
         mTN.mGravity = context.getResources().getInteger(
@@ -170,7 +181,7 @@
     public int getDuration() {
         return mDuration;
     }
-    
+
     /**
      * Set the margins of the view.
      *
@@ -226,7 +237,7 @@
     public int getXOffset() {
         return mTN.mX;
     }
-    
+
     /**
      * Return the Y offset in pixels to apply to the gravity's location.
      */
@@ -241,7 +252,7 @@
     public WindowManager.LayoutParams getWindowParams() {
         return mTN.mParams;
     }
-    
+
     /**
      * Make a standard toast that just contains a text view.
      *
@@ -253,14 +264,24 @@
      *
      */
     public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
-        Toast result = new Toast(context);
+        return makeText(context, null, text, duration);
+    }
+
+    /**
+     * Make a standard toast to display using the specified looper.
+     * If looper is null, Looper.myLooper() is used.
+     * @hide
+     */
+    public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
+            @NonNull CharSequence text, @Duration int duration) {
+        Toast result = new Toast(context, looper);
 
         LayoutInflater inflate = (LayoutInflater)
                 context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
         TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
         tv.setText(text);
-        
+
         result.mNextView = v;
         result.mDuration = duration;
 
@@ -290,7 +311,7 @@
     public void setText(@StringRes int resId) {
         setText(mContext.getText(resId));
     }
-    
+
     /**
      * Update the text in a Toast that was previously created using one of the makeText() methods.
      * @param s The new text for the Toast.
@@ -327,34 +348,7 @@
         private static final int SHOW = 0;
         private static final int HIDE = 1;
         private static final int CANCEL = 2;
-        final Handler mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case SHOW: {
-                        IBinder token = (IBinder) msg.obj;
-                        handleShow(token);
-                        break;
-                    }
-                    case HIDE: {
-                        handleHide();
-                        // Don't do this in handleHide() because it is also invoked by handleShow()
-                        mNextView = null;
-                        break;
-                    }
-                    case CANCEL: {
-                        handleHide();
-                        // Don't do this in handleHide() because it is also invoked by handleShow()
-                        mNextView = null;
-                        try {
-                            getService().cancelToast(mPackageName, TN.this);
-                        } catch (RemoteException e) {
-                        }
-                        break;
-                    }
-                }
-            }
-        };
+        final Handler mHandler;
 
         int mGravity;
         int mX, mY;
@@ -373,7 +367,7 @@
         static final long SHORT_DURATION_TIMEOUT = 4000;
         static final long LONG_DURATION_TIMEOUT = 7000;
 
-        TN(String packageName) {
+        TN(String packageName, @Nullable Looper looper) {
             // XXX This should be changed to use a Dialog, with a Theme.Toast
             // defined that sets up the layout params appropriately.
             final WindowManager.LayoutParams params = mParams;
@@ -388,6 +382,45 @@
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 
             mPackageName = packageName;
+
+            if (looper == null) {
+                // Use Looper.myLooper() if looper is not specified.
+                looper = Looper.myLooper();
+                if (looper == null) {
+                    throw new RuntimeException(
+                            "Can't toast on a thread that has not called Looper.prepare()");
+                }
+            }
+            mHandler = new Handler(looper, null) {
+                @Override
+                public void handleMessage(Message msg) {
+                    switch (msg.what) {
+                        case SHOW: {
+                            IBinder token = (IBinder) msg.obj;
+                            handleShow(token);
+                            break;
+                        }
+                        case HIDE: {
+                            handleHide();
+                            // Don't do this in handleHide() because it is also invoked by
+                            // handleShow()
+                            mNextView = null;
+                            break;
+                        }
+                        case CANCEL: {
+                            handleHide();
+                            // Don't do this in handleHide() because it is also invoked by
+                            // handleShow()
+                            mNextView = null;
+                            try {
+                                getService().cancelToast(mPackageName, TN.this);
+                            } catch (RemoteException e) {
+                            }
+                            break;
+                        }
+                    }
+                }
+            };
         }
 
         /**
@@ -469,7 +502,7 @@
             event.setPackageName(mView.getContext().getPackageName());
             mView.dispatchPopulateAccessibilityEvent(event);
             accessibilityManager.sendAccessibilityEvent(event);
-        }        
+        }
 
         public void handleHide() {
             if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 60df492..90b74ac 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -59,7 +59,8 @@
                     android:layout_marginLeft="16dp"
                     android:src="@android:drawable/ic_close"
                     android:alpha="0.54"
-                    android:background="?android:attr/selectableItemBackgroundBorderless">
+                    android:background="?android:attr/selectableItemBackgroundBorderless"
+                    android:contentDescription="@android:string/close_button_text">
                 </ImageView>
 
             </LinearLayout>
diff --git a/core/res/res/layout/notification_template_ambient_header.xml b/core/res/res/layout/notification_template_ambient_header.xml
new file mode 100644
index 0000000..c00acd5
--- /dev/null
+++ b/core/res/res/layout/notification_template_ambient_header.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- hack to work around <include /> not being supported at the top level -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:paddingStart="@dimen/notification_extra_margin_ambient"
+    android:paddingEnd="@dimen/notification_extra_margin_ambient"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <include
+        layout="@layout/notification_template_header"
+        android:theme="@style/Theme.Material.Notification.Ambient"/>
+</FrameLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3551bc9..2bd9ab9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2935,6 +2935,8 @@
   <java-symbol type="string" name="time_picker_text_input_mode_description"/>
   <java-symbol type="string" name="time_picker_radial_mode_description"/>
 
+  <java-symbol type="layout" name="notification_template_ambient_header" />
+
   <!-- resolver activity -->
   <java-symbol type="drawable" name="resolver_icon_placeholder" />
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 8a36120..40d36aa 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1869,9 +1869,9 @@
     public boolean sameAs(Bitmap other) {
         checkRecycled("Can't call sameAs on a recycled bitmap!");
         noteHardwareBitmapSlowCall();
-        other.noteHardwareBitmapSlowCall();
         if (this == other) return true;
         if (other == null) return false;
+        other.noteHardwareBitmapSlowCall();
         if (other.isRecycled()) {
             throw new IllegalArgumentException("Can't compare to a recycled bitmap!");
         }
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 6276ce3..c1f03fd 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -96,6 +96,10 @@
         WebSettings webSettings = mWebView.getSettings();
         webSettings.setJavaScriptEnabled(true);
         webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+        webSettings.setUseWideViewPort(true);
+        webSettings.setLoadWithOverviewMode(true);
+        webSettings.setSupportZoom(true);
+        webSettings.setBuiltInZoomControls(true);
         mWebViewClient = new MyWebViewClient();
         mWebView.setWebViewClient(mWebViewClient);
         mWebView.setWebChromeClient(new MyWebChromeClient());
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 9d6505b..46fbb24 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -240,7 +240,7 @@
     private int getColorForLevel(int percent) {
         // If we are in power save mode, always use the normal color.
         if (mPowerSaveEnabled) {
-            return mColors[mColors.length - 1];
+            return mIconTint;
         }
         int thresh, color = 0;
         for (int i = 0; i < mColors.length; i += 2) {
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
index 476f52b..f4501da 100644
--- a/packages/SystemUI/res/layout/hybrid_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -19,23 +19,22 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingStart="@*android:dimen/notification_content_margin_start"
-    android:paddingEnd="12dp"
-    android:gravity="bottom|start">
+    android:gravity="bottom|start"
+    style="?attr/hybridNotificationStyle">
     <TextView
         android:id="@+id/notification_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:paddingEnd="4dp"
-        android:singleLine="true"
         android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+        android:singleLine="true"
+        style="?attr/hybridNotificationTitleStyle"
     />
     <TextView
         android:id="@+id/notification_text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingEnd="4dp"
-        android:textAppearance="@*android:style/TextAppearance.Material.Notification"
         android:singleLine="true"
-        />
-</com.android.systemui.statusbar.notification.HybridNotificationView>
+        android:textAppearance="@*android:style/TextAppearance.Material.Notification"
+        style="?attr/hybridNotificationTextStyle"
+    />
+</com.android.systemui.statusbar.notification.HybridNotificationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hybrid_overflow_number.xml b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
index f3dde8d..792f424 100644
--- a/packages/SystemUI/res/layout/hybrid_overflow_number.xml
+++ b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
@@ -20,7 +20,7 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textAppearance="@*android:style/TextAppearance.Material.Notification"
-    android:paddingEnd="@*android:dimen/notification_content_margin_end"
+    android:paddingEnd="@dimen/group_overflow_number_padding"
     android:gravity="end"
     android:singleLine="true"
     />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer.xml b/packages/SystemUI/res/layout/qs_footer.xml
index 0a848c0..047f7aa 100644
--- a/packages/SystemUI/res/layout/qs_footer.xml
+++ b/packages/SystemUI/res/layout/qs_footer.xml
@@ -37,78 +37,79 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent" />
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="end">
 
-    <com.android.systemui.statusbar.phone.MultiUserSwitch
-        android:id="@+id/multi_user_switch"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_alignParentEnd="true"
-        android:background="@drawable/ripple_drawable"
-        android:focusable="true">
-
-        <ImageView
-            android:id="@+id/multi_user_avatar"
-            android:layout_width="@dimen/multi_user_avatar_expanded_size"
-            android:layout_height="@dimen/multi_user_avatar_expanded_size"
-            android:layout_gravity="center"
-            android:scaleType="centerInside"/>
-    </com.android.systemui.statusbar.phone.MultiUserSwitch>
-
-    <com.android.systemui.statusbar.AlphaOptimizedImageView
-        android:id="@android:id/edit"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:background="?android:attr/selectableItemBackgroundBorderless"
-        android:clickable="true"
-        android:clipToPadding="false"
-        android:contentDescription="@string/accessibility_quick_settings_edit"
-        android:focusable="true"
-        android:padding="16dp"
-        android:src="@drawable/ic_mode_edit"
-        android:tint="?android:attr/colorForeground"/>
-
-    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-        android:id="@+id/settings_button_container"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:clipChildren="false"
-        android:clipToPadding="false">
-
-        <com.android.systemui.statusbar.phone.SettingsButton
-            android:id="@+id/settings_button"
-            style="@android:style/Widget.Material.Button.Borderless"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
+        <com.android.systemui.statusbar.phone.MultiUserSwitch
+            android:id="@+id/multi_user_switch"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_alignParentEnd="true"
             android:background="@drawable/ripple_drawable"
-            android:contentDescription="@string/accessibility_quick_settings_settings"
-            android:src="@drawable/ic_settings_16dp"
-            android:tint="?android:attr/colorForeground"/>
+            android:focusable="true">
+
+            <ImageView
+                android:id="@+id/multi_user_avatar"
+                android:layout_width="@dimen/multi_user_avatar_expanded_size"
+                android:layout_height="@dimen/multi_user_avatar_expanded_size"
+                android:layout_gravity="center"
+                android:scaleType="centerInside"/>
+        </com.android.systemui.statusbar.phone.MultiUserSwitch>
 
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:id="@+id/tuner_icon"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingStart="36dp"
-            android:paddingEnd="4dp"
-            android:src="@drawable/tuner"
-            android:tint="?android:attr/textColorTertiary"
-            android:visibility="invisible"/>
+            android:id="@android:id/edit"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:clickable="true"
+            android:clipToPadding="false"
+            android:contentDescription="@string/accessibility_quick_settings_edit"
+            android:focusable="true"
+            android:padding="16dp"
+            android:src="@drawable/ic_mode_edit"
+            android:tint="?android:attr/colorForeground"/>
 
-    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+            android:id="@+id/settings_button_container"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:clipChildren="false"
+            android:clipToPadding="false">
 
-    <com.android.systemui.statusbar.phone.ExpandableIndicator
-        android:id="@+id/expand_indicator"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:clipToPadding="false"
-        android:clickable="true"
-        android:focusable="true"
-        android:background="?android:attr/selectableItemBackgroundBorderless"
-        android:contentDescription="@string/accessibility_quick_settings_expand"
-        android:padding="14dp" />
+            <com.android.systemui.statusbar.phone.SettingsButton
+                android:id="@+id/settings_button"
+                style="@android:style/Widget.Material.Button.Borderless"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="@drawable/ripple_drawable"
+                android:contentDescription="@string/accessibility_quick_settings_settings"
+                android:src="@drawable/ic_settings_16dp"
+                android:tint="?android:attr/colorForeground"/>
+
+            <com.android.systemui.statusbar.AlphaOptimizedImageView
+                android:id="@+id/tuner_icon"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingStart="36dp"
+                android:paddingEnd="4dp"
+                android:src="@drawable/tuner"
+                android:tint="?android:attr/textColorTertiary"
+                android:visibility="invisible"/>
+
+        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+
+        <com.android.systemui.statusbar.phone.ExpandableIndicator
+            android:id="@+id/expand_indicator"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:clipToPadding="false"
+            android:clickable="true"
+            android:focusable="true"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:contentDescription="@string/accessibility_quick_settings_expand"
+            android:padding="14dp" />
+    </LinearLayout>
 
 </com.android.systemui.qs.QSFooter>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 008fcf0..a57b17e 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -108,6 +108,12 @@
         <attr name="android:layout" />
     </declare-styleable>
 
+    <declare-styleable name="HybridNotificationTheme">
+        <attr name="hybridNotificationStyle" format="reference" />
+        <attr name="hybridNotificationTitleStyle" format="reference" />
+        <attr name="hybridNotificationTextStyle" format="reference" />
+    </declare-styleable>
+
     <declare-styleable name="AutoSizingList">
         <!-- Whether AutoSizingList will show only as many items as fit on screen and
              remove extra items instead of scrolling. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f072849..5374673 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -57,6 +57,11 @@
     <!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
     <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
 
+    <dimen name="group_overflow_number_size">@*android:dimen/notification_text_size</dimen>
+    <dimen name="group_overflow_number_size_dark">16sp</dimen>
+    <dimen name="group_overflow_number_padding">@*android:dimen/notification_content_margin_end</dimen>
+    <dimen name="group_overflow_number_extra_padding_dark">@*android:dimen/notification_extra_margin_ambient</dimen>
+
     <!-- max height of a notification such that the content can still fade out when closing -->
     <dimen name="max_notification_fadeout_height">100dp</dimen>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index dbdbd1e..9650cea 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -82,6 +82,56 @@
         <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
     </style>
 
+    <!-- HybridNotification themes and styles -->
+
+    <style name="HybridNotification">
+        <item name="hybridNotificationStyle">@style/hybrid_notification</item>
+        <item name="hybridNotificationTitleStyle">@style/hybrid_notification_title</item>
+        <item name="hybridNotificationTextStyle">@style/hybrid_notification_text</item>
+    </style>
+
+    <style name="HybridNotification.Ambient">
+        <item name="hybridNotificationStyle">@style/hybrid_notification_ambient</item>
+        <item name="hybridNotificationTitleStyle">@style/hybrid_notification_title_ambient</item>
+        <item name="hybridNotificationTextStyle">@style/hybrid_notification_text_ambient</item>
+    </style>
+
+    <style name="hybrid_notification_ambient">
+        <item name="android:paddingStart">@*android:dimen/notification_extra_margin_ambient</item>
+        <item name="android:paddingEnd">@*android:dimen/notification_extra_margin_ambient</item>
+        <item name="android:orientation">vertical</item>
+        <item name="android:paddingBottom">23.5dp</item>
+    </style>
+
+    <style name="hybrid_notification">
+        <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
+        <item name="android:paddingEnd">12dp</item>
+    </style>
+
+    <style name="hybrid_notification_title_ambient">
+        <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
+        <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
+        <item name="android:textSize">20sp</item>
+        <item name="android:textColor">#ffffffff</item>
+    </style>
+
+    <style name="hybrid_notification_title">
+        <item name="android:paddingEnd">4dp</item>
+    </style>
+
+    <style name="hybrid_notification_text_ambient">
+        <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
+        <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">#eeffffff</item>
+        <item name="android:layout_marginTop">4dp</item>
+    </style>
+
+    <style name="hybrid_notification_text">
+        <item name="android:paddingEnd">4dp</item>
+    </style>
+
+
     <style name="TextAppearance.StatusBar.HeadsUp"
         parent="@*android:style/TextAppearance.StatusBar">
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 4f484b6..063f5df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -33,6 +33,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -63,7 +64,7 @@
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 import com.android.systemui.tuner.TunerService;
 
-public class QSFooter extends LinearLayout implements
+public class QSFooter extends FrameLayout implements
         NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
         SignalCallback {
     private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 21bf462..49d20a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -234,6 +234,7 @@
     private boolean mUseIncreasedHeadsUpHeight;
     private float mTranslationWhenRemoved;
     private boolean mWasChildInGroupWhenRemoved;
+    private int mNotificationColorAmbient;
 
     @Override
     public boolean isGroupExpansionChanging() {
@@ -876,12 +877,18 @@
         mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
                 getStatusBarNotification().getNotification().color,
                 getBackgroundColorWithoutTint());
+        mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
+                getStatusBarNotification().getNotification().color);
     }
 
     public HybridNotificationView getSingleLineView() {
         return mPrivateLayout.getSingleLineView();
     }
 
+    public HybridNotificationView getAmbientSingleLineView() {
+        return getShowingLayout().getAmbientSingleLineChild();
+    }
+
     public boolean isOnKeyguard() {
         return mOnKeyguard;
     }
@@ -1145,6 +1152,10 @@
         return mNotificationInflater;
     }
 
+    public int getNotificationColorAmbient() {
+        return mNotificationColorAmbient;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -1523,13 +1534,11 @@
             return mGuts.getIntrinsicHeight();
         } else if ((isChildInGroup() && !isGroupExpanded())) {
             return mPrivateLayout.getMinHeight();
-        } else if (mShowAmbient) {
-            return getAmbientHeight();
         } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
             return getMinHeight();
-        } else if (mIsSummaryWithChildren && !mOnKeyguard) {
+        } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
             return mChildrenContainer.getIntrinsicHeight();
-        } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
+        } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
             if (isPinned() || mHeadsupDisappearRunning) {
                 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
             } else if (isExpanded()) {
@@ -1544,6 +1553,10 @@
         }
     }
 
+    private boolean isHeadsUpAllowed() {
+        return !mOnKeyguard && !mShowAmbient;
+    }
+
     @Override
     public boolean isGroupExpanded() {
         return mGroupManager.isGroupExpanded(mStatusBarNotification);
@@ -1874,24 +1887,17 @@
     public int getMinHeight() {
         if (mGuts != null && mGuts.isExposed()) {
             return mGuts.getIntrinsicHeight();
-        } else if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
+        } else if (isHeadsUpAllowed() && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
                 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
         } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
             return mChildrenContainer.getMinHeight();
-        } else if (!mOnKeyguard && mIsHeadsUp) {
+        } else if (isHeadsUpAllowed() && mIsHeadsUp) {
             return mHeadsUpHeight;
         }
         NotificationContentView showingLayout = getShowingLayout();
         return showingLayout.getMinHeight();
     }
 
-    private int getAmbientHeight() {
-        NotificationContentView showingLayout = getShowingLayout();
-        return showingLayout.getAmbientChild() != null
-                ? showingLayout.getAmbientChild().getHeight()
-                : getCollapsedHeight();
-    }
-
     @Override
     public int getCollapsedHeight() {
         if (mIsSummaryWithChildren && !mShowingPublic) {
@@ -2126,10 +2132,17 @@
     public void setShowAmbient(boolean showAmbient) {
         if (showAmbient != mShowAmbient) {
             mShowAmbient = showAmbient;
+            if (mChildrenContainer != null) {
+                mChildrenContainer.notifyShowAmbientChanged();
+            }
             notifyHeightChanged(false /* needsAnimation */);
         }
     }
 
+    public boolean isShowingAmbient() {
+        return mShowAmbient;
+    }
+
     public void setAboveShelf(boolean aboveShelf) {
         mAboveShelf = aboveShelf;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index e7bf983..baf0c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -54,6 +54,7 @@
     private static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
     private static final int VISIBLE_TYPE_AMBIENT = 4;
+    private static final int VISIBLE_TYPE_AMBIENT_SINGLELINE = 5;
     public static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
@@ -65,6 +66,7 @@
     private View mHeadsUpChild;
     private HybridNotificationView mSingleLineView;
     private View mAmbientChild;
+    private HybridNotificationView mAmbientSingleLineChild;
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
@@ -252,6 +254,27 @@
                             : MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
         }
+        if (mAmbientSingleLineChild != null) {
+            int size = Math.min(maxSize, mNotificationAmbientHeight);
+            ViewGroup.LayoutParams layoutParams = mAmbientSingleLineChild.getLayoutParams();
+            boolean useExactly = false;
+            if (layoutParams.height >= 0) {
+                // An actual height is set
+                size = Math.min(size, layoutParams.height);
+                useExactly = true;
+            }
+            int ambientSingleLineWidthSpec = widthMeasureSpec;
+            if (mSingleLineWidthIndention != 0
+                    && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
+                ambientSingleLineWidthSpec = MeasureSpec.makeMeasureSpec(
+                        width - mSingleLineWidthIndention + mAmbientSingleLineChild.getPaddingEnd(),
+                        MeasureSpec.EXACTLY);
+            }
+            mAmbientSingleLineChild.measure(ambientSingleLineWidthSpec,
+                    MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
+                            : MeasureSpec.AT_MOST));
+            maxChildHeight = Math.max(maxChildHeight, mAmbientSingleLineChild.getMeasuredHeight());
+        }
         int ownHeight = Math.min(maxChildHeight, maxSize);
         setMeasuredDimension(width, ownHeight);
     }
@@ -345,6 +368,10 @@
         return mAmbientChild;
     }
 
+    public HybridNotificationView getAmbientSingleLineChild() {
+        return mAmbientSingleLineChild;
+    }
+
     public void setContractedChild(View child) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
@@ -533,6 +560,9 @@
         int hint;
         if (mAmbientChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
             hint = mAmbientChild.getHeight();
+        } else if (mAmbientSingleLineChild != null && isVisibleOrTransitioning(
+                VISIBLE_TYPE_AMBIENT_SINGLELINE)) {
+            hint = mAmbientSingleLineChild.getHeight();
         } else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
             hint = mHeadsUpChild.getHeight();
         } else if (mExpandedChild != null) {
@@ -622,7 +652,9 @@
     }
 
     public int getMaxHeight() {
-        if (mExpandedChild != null) {
+        if (mContainingNotification.isShowingAmbient()) {
+            return getShowingAmbientView().getHeight();
+        } else if (mExpandedChild != null) {
             return mExpandedChild.getHeight();
         } else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
             return mHeadsUpChild.getHeight();
@@ -635,13 +667,24 @@
     }
 
     public int getMinHeight(boolean likeGroupExpanded) {
-        if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
+        if (mContainingNotification.isShowingAmbient()) {
+            return getShowingAmbientView().getHeight();
+        } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
             return mContractedChild.getHeight();
         } else {
             return mSingleLineView.getHeight();
         }
     }
 
+    public View getShowingAmbientView() {
+        View v = mIsChildInGroup ? mAmbientSingleLineChild : mAmbientChild;
+        if (v != null) {
+            return v;
+        } else {
+            return mContractedChild;
+        }
+    }
+
     private boolean isGroupExpanded() {
         return mGroupManager.isGroupExpanded(mStatusBarNotification);
     }
@@ -723,6 +766,8 @@
         forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
         forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
         forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_AMBIENT_SINGLELINE, mAmbientSingleLineChild,
+                mAmbientSingleLineChild);
         fireExpandedVisibleListenerIfVisible();
         // forceUpdateVisibilities cancels outstanding animations without updating the
         // mAnimationStartVisibleType. Do so here instead.
@@ -791,6 +836,8 @@
                 mSingleLineView, mSingleLineView);
         updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
                 mAmbientChild, mAmbientWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT_SINGLELINE,
+                mAmbientSingleLineChild, mAmbientSingleLineChild);
         fireExpandedVisibleListenerIfVisible();
         // updateViewVisibilities cancels outstanding animations without updating the
         // mAnimationStartVisibleType. Do so here instead.
@@ -853,6 +900,8 @@
                 return mSingleLineView;
             case VISIBLE_TYPE_AMBIENT:
                 return mAmbientWrapper;
+            case VISIBLE_TYPE_AMBIENT_SINGLELINE:
+                return mAmbientSingleLineChild;
             default:
                 return mContractedWrapper;
         }
@@ -872,6 +921,8 @@
                 return mSingleLineView;
             case VISIBLE_TYPE_AMBIENT:
                 return mAmbientChild;
+            case VISIBLE_TYPE_AMBIENT_SINGLELINE:
+                return mAmbientSingleLineChild;
             default:
                 return mContractedChild;
         }
@@ -896,9 +947,14 @@
      * @return one of the static enum types in this view, calculated form the current state
      */
     public int calculateVisibleType() {
-        if (mDark && !mIsChildInGroup) {
-            // TODO: Handle notification groups
-            return VISIBLE_TYPE_AMBIENT;
+        if (mContainingNotification.isShowingAmbient()) {
+            if (mIsChildInGroup && mAmbientSingleLineChild != null) {
+                return VISIBLE_TYPE_AMBIENT_SINGLELINE;
+            } else if (mAmbientChild != null) {
+                return VISIBLE_TYPE_AMBIENT;
+            } else {
+                return VISIBLE_TYPE_CONTRACTED;
+            }
         }
         if (mUserExpanding) {
             int height = !mIsChildInGroup || isGroupExpanded()
@@ -1021,13 +1077,13 @@
         if (mAmbientChild != null) {
             mAmbientWrapper.setIsChildInGroup(mIsChildInGroup);
         }
-        updateSingleLineView();
+        updateAllSingleLineViews();
     }
 
     public void onNotificationUpdated(NotificationData.Entry entry) {
         mStatusBarNotification = entry.notification;
         mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
-        updateSingleLineView();
+        updateAllSingleLineViews();
         if (mContractedChild != null) {
             mContractedWrapper.notifyContentUpdated(entry.row);
         }
@@ -1048,6 +1104,10 @@
         mPreviousHeadsUpRemoteInputIntent = null;
     }
 
+    private void updateAllSingleLineViews() {
+        updateSingleLineView();
+        updateAmbientSingleLineView();
+    }
     private void updateSingleLineView() {
         if (mIsChildInGroup) {
             mSingleLineView = mHybridGroupManager.bindFromNotification(
@@ -1058,6 +1118,16 @@
         }
     }
 
+    private void updateAmbientSingleLineView() {
+        if (mIsChildInGroup) {
+            mAmbientSingleLineChild = mHybridGroupManager.bindAmbientFromNotification(
+                    mAmbientSingleLineChild, mStatusBarNotification.getNotification());
+        } else if (mAmbientSingleLineChild != null) {
+            removeView(mAmbientSingleLineChild);
+            mAmbientSingleLineChild = null;
+        }
+    }
+
     private void applyRemoteInput(final NotificationData.Entry entry) {
         if (mRemoteInputController == null) {
             return;
@@ -1255,7 +1325,7 @@
         if (mIsChildInGroup && mSingleLineView != null) {
             removeView(mSingleLineView);
             mSingleLineView = null;
-            updateSingleLineView();
+            updateAllSingleLineViews();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
index 7373607..3ed8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -18,20 +18,14 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.text.BidiFormatter;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
-import android.text.style.TextAppearanceSpan;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-
-import java.util.List;
 
 /**
  * A class managing hybrid groups that include {@link HybridNotificationView} and the notification
@@ -40,16 +34,37 @@
 public class HybridGroupManager {
 
     private final Context mContext;
-    private ViewGroup mParent;
+    private final NotificationDozeHelper mDozer;
+    private final ViewGroup mParent;
+
+    private final float mOverflowNumberSizeDark;
+    private final int mOverflowNumberPaddingDark;
+    private final float mOverflowNumberSize;
+    private final int mOverflowNumberPadding;
+
     private int mOverflowNumberColor;
+    private int mOverflowNumberColorDark;
+    private float mDarkAmount = 0f;
 
     public HybridGroupManager(Context ctx, ViewGroup parent) {
         mContext = ctx;
         mParent = parent;
+        mDozer = new NotificationDozeHelper();
+
+        Resources res = mContext.getResources();
+        mOverflowNumberSize = res.getDimensionPixelSize(
+                R.dimen.group_overflow_number_size);
+        mOverflowNumberSizeDark = res.getDimensionPixelSize(
+                R.dimen.group_overflow_number_size_dark);
+        mOverflowNumberPadding = res.getDimensionPixelSize(
+                R.dimen.group_overflow_number_padding);
+        mOverflowNumberPaddingDark = mOverflowNumberPadding + res.getDimensionPixelSize(
+                R.dimen.group_overflow_number_extra_padding_dark);
     }
 
-    private HybridNotificationView inflateHybridView() {
-        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+    private HybridNotificationView inflateHybridViewWithStyle(int style) {
+        LayoutInflater inflater = new ContextThemeWrapper(mContext, style)
+                .getSystemService(LayoutInflater.class);
         HybridNotificationView hybrid = (HybridNotificationView) inflater.inflate(
                 R.layout.hybrid_notification, mParent, false);
         mParent.addView(hybrid);
@@ -66,11 +81,13 @@
     }
 
     private void updateOverFlowNumberColor(TextView numberView) {
-        numberView.setTextColor(mOverflowNumberColor);
+        numberView.setTextColor(NotificationUtils.interpolateColors(
+                mOverflowNumberColor, mOverflowNumberColorDark, mDarkAmount));
     }
 
-    public void setOverflowNumberColor(TextView numberView, int overflowNumberColor) {
-        mOverflowNumberColor = overflowNumberColor;
+    public void setOverflowNumberColor(TextView numberView, int colorRegular, int colorDark) {
+        mOverflowNumberColor = colorRegular;
+        mOverflowNumberColorDark = colorDark;
         if (numberView != null) {
             updateOverFlowNumberColor(numberView);
         }
@@ -78,8 +95,20 @@
 
     public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
             Notification notification) {
+        return bindFromNotificationWithStyle(reusableView, notification,
+                R.style.HybridNotification);
+    }
+
+    public HybridNotificationView bindAmbientFromNotification(HybridNotificationView reusableView,
+            Notification notification) {
+        return bindFromNotificationWithStyle(reusableView, notification,
+                R.style.HybridNotification_Ambient);
+    }
+
+    private HybridNotificationView bindFromNotificationWithStyle(
+            HybridNotificationView reusableView, Notification notification, int style) {
         if (reusableView == null) {
-            reusableView = inflateHybridView();
+            reusableView = inflateHybridViewWithStyle(style);
         }
         CharSequence titleText = resolveTitle(notification);
         CharSequence contentText = resolveText(notification);
@@ -118,4 +147,16 @@
         reusableView.setContentDescription(contentDescription);
         return reusableView;
     }
+
+    public void setOverflowNumberDark(TextView view, boolean dark, boolean fade, long delay) {
+        mDozer.setIntensityDark((f)->{
+            mDarkAmount = f;
+            updateOverFlowNumberColor(view);
+        }, dark, fade, delay);
+        view.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                dark ? mOverflowNumberSizeDark : mOverflowNumberSize);
+        int paddingEnd = dark ? mOverflowNumberPaddingDark : mOverflowNumberPadding;
+        view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), paddingEnd,
+                view.getPaddingBottom());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index fe249a6..cb1f44e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -30,7 +30,6 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationHeaderUtil;
@@ -39,7 +38,6 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -52,6 +50,7 @@
     private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
     private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
     private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
+    private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 3;
     private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
         private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
 
@@ -70,7 +69,6 @@
     private int mNotificationHeaderMargin;
     private int mNotificatonTopPadding;
     private float mCollapsedBottompadding;
-    private ViewInvertHelper mOverflowInvertHelper;
     private boolean mChildrenExpanded;
     private ExpandableNotificationRow mContainingNotification;
     private TextView mOverflowNumber;
@@ -85,12 +83,14 @@
     private NotificationViewWrapper mNotificationHeaderWrapper;
     private NotificationHeaderView mNotificationHeaderLowPriority;
     private NotificationViewWrapper mNotificationHeaderWrapperLowPriority;
+    private ViewGroup mNotificationHeaderAmbient;
+    private NotificationViewWrapper mNotificationHeaderWrapperAmbient;
     private NotificationHeaderUtil mHeaderUtil;
     private ViewState mHeaderViewState;
     private int mClipBottomAmount;
     private boolean mIsLowPriority;
     private OnClickListener mHeaderClickListener;
-    private boolean mShowingNormalHeader;
+    private ViewGroup mCurrentHeader;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -152,6 +152,11 @@
                     mNotificationHeaderLowPriority.getMeasuredWidth(),
                     mNotificationHeaderLowPriority.getMeasuredHeight());
         }
+        if (mNotificationHeaderAmbient != null) {
+            mNotificationHeaderAmbient.layout(0, 0,
+                    mNotificationHeaderAmbient.getMeasuredWidth(),
+                    mNotificationHeaderAmbient.getMeasuredHeight());
+        }
     }
 
     @Override
@@ -203,6 +208,10 @@
             headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
             mNotificationHeaderLowPriority.measure(widthMeasureSpec, headerHeightSpec);
         }
+        if (mNotificationHeaderAmbient != null) {
+            headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
+            mNotificationHeaderAmbient.measure(widthMeasureSpec, headerHeightSpec);
+        }
 
         setMeasuredDimension(width, height);
     }
@@ -273,7 +282,7 @@
         StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
         final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
                 notification.getNotification());
-        RemoteViews header = builder.makeNotificationHeader();
+        RemoteViews header = builder.makeNotificationHeader(false /* ambient */);
         if (mNotificationHeader == null) {
             mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
             final View expandButton = mNotificationHeader.findViewById(
@@ -289,10 +298,33 @@
         }
         mNotificationHeaderWrapper.notifyContentUpdated(mContainingNotification);
         recreateLowPriorityHeader(builder);
-        updateHeaderVisibility(false /* animate */);
+        recreateAmbientHeader(builder);
+        resetHeaderVisibilityIfNeeded(mNotificationHeader, calculateDesiredHeader());
         updateChildrenHeaderAppearance();
     }
 
+    private void recreateAmbientHeader(Notification.Builder builder) {
+        RemoteViews header;
+        StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
+        if (builder == null) {
+            builder = Notification.Builder.recoverBuilder(getContext(),
+                    notification.getNotification());
+        }
+        header = builder.makeNotificationHeader(true /* ambient */);
+        if (mNotificationHeaderAmbient == null) {
+            mNotificationHeaderAmbient = (ViewGroup) header.apply(getContext(), this);
+            mNotificationHeaderWrapperAmbient = NotificationViewWrapper.wrap(getContext(),
+                    mNotificationHeaderAmbient, mContainingNotification);
+            mNotificationHeaderWrapperAmbient.notifyContentUpdated(mContainingNotification);
+            addView(mNotificationHeaderAmbient, 0);
+            invalidate();
+        } else {
+            header.reapply(getContext(), mNotificationHeaderAmbient);
+        }
+        resetHeaderVisibilityIfNeeded(mNotificationHeaderAmbient, calculateDesiredHeader());
+        mNotificationHeaderWrapperAmbient.notifyContentUpdated(mContainingNotification);
+    }
+
     /**
      * Recreate the low-priority header.
      *
@@ -322,6 +354,7 @@
                 header.reapply(getContext(), mNotificationHeaderLowPriority);
             }
             mNotificationHeaderWrapperLowPriority.notifyContentUpdated(mContainingNotification);
+            resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, calculateDesiredHeader());
         } else {
             removeView(mNotificationHeaderLowPriority);
             mNotificationHeaderLowPriority = null;
@@ -339,10 +372,6 @@
         if (childCount > maxAllowedVisibleChildren) {
             mOverflowNumber = mHybridGroupManager.bindOverflowNumber(
                     mOverflowNumber, childCount - maxAllowedVisibleChildren);
-            if (mOverflowInvertHelper == null) {
-                mOverflowInvertHelper = new ViewInvertHelper(mOverflowNumber,
-                        NotificationPanelView.DOZE_ANIMATION_DURATION);
-            }
             if (mGroupOverFlowState == null) {
                 mGroupOverFlowState = new ViewState();
                 mNeverAppliedGroupState = true;
@@ -360,7 +389,6 @@
                 });
             }
             mOverflowNumber = null;
-            mOverflowInvertHelper = null;
             mGroupOverFlowState = null;
         }
     }
@@ -449,6 +477,7 @@
         if (mUserLocked) {
             expandFactor = getGroupExpandFraction();
         }
+        boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isShowingAmbient();
         for (int i = 0; i < childCount; i++) {
             if (visibleChildren >= maxAllowedVisibleChildren) {
                 break;
@@ -458,7 +487,7 @@
                     intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
                             expandFactor);
                 } else {
-                    intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding;
+                    intrinsicHeight += childrenExpanded ? mDividerHeight : mChildPadding;
                 }
             } else {
                 if (mUserLocked) {
@@ -467,7 +496,7 @@
                             mNotificatonTopPadding + mDividerHeight,
                             expandFactor);
                 } else {
-                    intrinsicHeight += mChildrenExpanded
+                    intrinsicHeight += childrenExpanded
                             ? mNotificatonTopPadding + mDividerHeight
                             : 0;
                 }
@@ -480,7 +509,7 @@
         if (mUserLocked) {
             intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f,
                     expandFactor);
-        } else if (!mChildrenExpanded) {
+        } else if (!childrenExpanded) {
             intrinsicHeight += mCollapsedBottompadding;
         }
         return intrinsicHeight;
@@ -515,7 +544,7 @@
                     yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
                             expandFactor);
                 } else {
-                    yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+                    yPosition += childrenExpanded ? mDividerHeight : mChildPadding;
                 }
             } else {
                 if (expandingToExpandedGroup) {
@@ -524,7 +553,7 @@
                             mNotificatonTopPadding + mDividerHeight,
                             expandFactor);
                 } else {
-                    yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+                    yPosition += childrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
                 }
                 firstChild = false;
             }
@@ -560,15 +589,21 @@
             ExpandableNotificationRow overflowView = mChildren.get(Math.min(
                     getMaxAllowedVisibleChildren(true /* likeCollpased */), childCount) - 1);
             mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
-            if (!mChildrenExpanded) {
-                if (mUserLocked) {
-                    HybridNotificationView singleLineView = overflowView.getSingleLineView();
-                    View mirrorView = singleLineView.getTextView();
+
+            if (mContainingNotification.isShowingAmbient() || !mChildrenExpanded) {
+                HybridNotificationView alignView = null;
+                if (mContainingNotification.isShowingAmbient()) {
+                    alignView = overflowView.getAmbientSingleLineView();
+                } else if (mUserLocked) {
+                    alignView = overflowView.getSingleLineView();
+                }
+                if (alignView != null) {
+                    View mirrorView = alignView.getTextView();
                     if (mirrorView.getVisibility() == GONE) {
-                        mirrorView = singleLineView.getTitleView();
+                        mirrorView = alignView.getTitleView();
                     }
                     if (mirrorView.getVisibility() == GONE) {
-                        mirrorView = singleLineView;
+                        mirrorView = alignView;
                     }
                     mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
                             mirrorView, overflowView);
@@ -620,6 +655,9 @@
     }
 
     private int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
+        if (mContainingNotification.isShowingAmbient()) {
+            return NUMBER_OF_CHILDREN_WHEN_AMBIENT;
+        }
         if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())) {
             return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
         }
@@ -794,40 +832,78 @@
         return mNotificationHeaderLowPriority;
     }
 
+    public void notifyShowAmbientChanged() {
+        updateHeaderVisibility(false);
+    }
+
     private void updateHeaderVisibility(boolean animate) {
-        NotificationHeaderView visibleHeader = mNotificationHeader;
-        NotificationHeaderView hiddenHeader = mNotificationHeaderLowPriority;
-        boolean normalHeaderVisible = true;
-        if (showingAsLowPriority()) {
-            visibleHeader = mNotificationHeaderLowPriority;
-            hiddenHeader = mNotificationHeader;
-            normalHeaderVisible = false;
+        ViewGroup desiredHeader;
+        ViewGroup currentHeader = mCurrentHeader;
+        desiredHeader = calculateDesiredHeader();
+
+        if (currentHeader == desiredHeader) {
+            return;
         }
+        if (desiredHeader == mNotificationHeaderAmbient
+                || currentHeader == mNotificationHeaderAmbient) {
+            animate = false;
+        }
+
         if (animate) {
-            if (visibleHeader != null && hiddenHeader != null
-                    && mShowingNormalHeader != normalHeaderVisible) {
-                hiddenHeader.setVisibility(VISIBLE);
-                visibleHeader.setVisibility(VISIBLE);
-                NotificationViewWrapper visibleWrapper = getWrapperForView(visibleHeader);
-                NotificationViewWrapper hiddenWrapper = getWrapperForView(hiddenHeader);
+            if (desiredHeader != null && currentHeader != null) {
+                currentHeader.setVisibility(VISIBLE);
+                desiredHeader.setVisibility(VISIBLE);
+                NotificationViewWrapper visibleWrapper = getWrapperForView(desiredHeader);
+                NotificationViewWrapper hiddenWrapper = getWrapperForView(currentHeader);
                 visibleWrapper.transformFrom(hiddenWrapper);
                 hiddenWrapper.transformTo(visibleWrapper, () -> updateHeaderVisibility(false));
-                startChildAlphaAnimations(normalHeaderVisible);
+                startChildAlphaAnimations(desiredHeader == mNotificationHeader);
             } else {
                 animate = false;
             }
         }
         if (!animate) {
-            if (visibleHeader != null) {
-                getWrapperForView(visibleHeader).setVisible(true);
-                visibleHeader.setVisibility(VISIBLE);
+            if (desiredHeader != null) {
+                getWrapperForView(desiredHeader).setVisible(true);
+                desiredHeader.setVisibility(VISIBLE);
             }
-            if (hiddenHeader != null) {
-                getWrapperForView(hiddenHeader).setVisible(false);
-                hiddenHeader.setVisibility(INVISIBLE);
+            if (currentHeader != null) {
+                getWrapperForView(currentHeader).setVisible(false);
+                currentHeader.setVisibility(INVISIBLE);
             }
         }
-        mShowingNormalHeader = normalHeaderVisible;
+
+        resetHeaderVisibilityIfNeeded(mNotificationHeader, desiredHeader);
+        resetHeaderVisibilityIfNeeded(mNotificationHeaderAmbient, desiredHeader);
+        resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, desiredHeader);
+
+        mCurrentHeader = currentHeader;
+    }
+
+    private void resetHeaderVisibilityIfNeeded(View header, View desiredHeader) {
+        if (header == null) {
+            return;
+        }
+        if (header != mCurrentHeader && header != desiredHeader) {
+            getWrapperForView(header).setVisible(false);
+            header.setVisibility(INVISIBLE);
+        }
+        if (header == desiredHeader && header.getVisibility() != VISIBLE) {
+            getWrapperForView(header).setVisible(true);
+            header.setVisibility(VISIBLE);
+        }
+    }
+
+    private ViewGroup calculateDesiredHeader() {
+        ViewGroup desiredHeader;
+        if (mContainingNotification.isShowingAmbient()) {
+            desiredHeader = mNotificationHeaderAmbient;
+        } else if (showingAsLowPriority()) {
+            desiredHeader = mNotificationHeaderLowPriority;
+        } else {
+            desiredHeader = mNotificationHeader;
+        }
+        return desiredHeader;
     }
 
     private void startChildAlphaAnimations(boolean toVisible) {
@@ -861,10 +937,13 @@
 
     }
 
-    private NotificationViewWrapper getWrapperForView(NotificationHeaderView visibleHeader) {
+    private NotificationViewWrapper getWrapperForView(View visibleHeader) {
         if (visibleHeader == mNotificationHeader) {
             return mNotificationHeaderWrapper;
         }
+        if (visibleHeader == mNotificationHeaderAmbient) {
+            return mNotificationHeaderWrapperAmbient;
+        }
         return mNotificationHeaderWrapperLowPriority;
     }
 
@@ -971,7 +1050,9 @@
     }
 
     public int getMinHeight() {
-        return getMinHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
+        return getMinHeight(mContainingNotification.isShowingAmbient()
+                ? NUMBER_OF_CHILDREN_WHEN_AMBIENT
+                : NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
     }
 
     public int getCollapsedHeight() {
@@ -1016,7 +1097,7 @@
 
     public void setDark(boolean dark, boolean fade, long delay) {
         if (mOverflowNumber != null) {
-            mOverflowInvertHelper.setInverted(dark, fade, delay);
+            mHybridGroupManager.setOverflowNumberDark(mOverflowNumber, dark, fade, delay);
         }
         mNotificationHeaderWrapper.setDark(dark, fade, delay);
     }
@@ -1030,6 +1111,10 @@
             removeView(mNotificationHeaderLowPriority);
             mNotificationHeaderLowPriority = null;
         }
+        if (mNotificationHeaderAmbient != null) {
+            removeView(mNotificationHeaderAmbient);
+            mNotificationHeaderAmbient = null;
+        }
         recreateNotificationHeader(listener);
         initDimens();
         for (int i = 0; i < mDividers.size(); i++) {
@@ -1042,7 +1127,6 @@
         }
         removeView(mOverflowNumber);
         mOverflowNumber = null;
-        mOverflowInvertHelper = null;
         mGroupOverFlowState = null;
         updateGroupOverflow();
     }
@@ -1061,7 +1145,8 @@
 
     public void onNotificationUpdated() {
         mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
-                mContainingNotification.getNotificationColor());
+                mContainingNotification.getNotificationColor(),
+                mContainingNotification.getNotificationColorAmbient());
     }
 
     public int getPositionInLinearLayout(View childInGroup) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 20a6d14..bff39b3 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -56,6 +56,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityThread;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -3562,7 +3563,6 @@
     private void showInputMethodMenu(boolean showAuxSubtypes) {
         if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
 
-        final Context context = mContext;
         final boolean isScreenLocked = isScreenLocked();
 
         final String lastInputMethodId = mSettings.getSelectedInputMethod();
@@ -3610,7 +3610,8 @@
                 }
             }
 
-            final Context settingsContext = new ContextThemeWrapper(context,
+            final Context settingsContext = new ContextThemeWrapper(
+                    ActivityThread.currentActivityThread().getSystemUiContext(),
                     com.android.internal.R.style.Theme_DeviceDefault_Settings);
 
             mDialogBuilder = new AlertDialog.Builder(settingsContext);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 23a1a78..7dcd6cd 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3269,12 +3269,8 @@
         final boolean warningEnabled = Settings.System.getInt(getContext().getContentResolver(),
                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0) != 0;
         if (warningEnabled || Build.IS_DEBUGGABLE) {
-            try {
-                Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG);
-                toast.show();
-            } catch (RuntimeException e) {
-                Slog.w(TAG, "Unable to toast with text: " + toastText, e);
-            }
+            Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText, Toast.LENGTH_LONG);
+            toast.show();
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6d13c85..f1e4e12 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1741,13 +1741,14 @@
 
                         int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
 
-                        if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
+                        final UserHandle user = args.getUser();
+                        if (getDefaultVerificationResponse(user)
+                                == PackageManager.VERIFICATION_ALLOW) {
                             Slog.i(TAG, "Continuing with installation of " + originUri);
                             state.setVerifierResponse(Binder.getCallingUid(),
                                     PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                             broadcastPackageVerified(verificationId, originUri,
-                                    PackageManager.VERIFICATION_ALLOW,
-                                    state.getInstallArgs().getUser());
+                                    PackageManager.VERIFICATION_ALLOW, user);
                             try {
                                 ret = args.copyApk(mContainerService, true);
                             } catch (RemoteException e) {
@@ -1755,8 +1756,7 @@
                             }
                         } else {
                             broadcastPackageVerified(verificationId, originUri,
-                                    PackageManager.VERIFICATION_REJECT,
-                                    state.getInstallArgs().getUser());
+                                    PackageManager.VERIFICATION_REJECT, user);
                         }
 
                         Trace.asyncTraceEnd(
@@ -14207,7 +14207,10 @@
      *
      * @return default verification response code
      */
-    private int getDefaultVerificationResponse() {
+    private int getDefaultVerificationResponse(UserHandle user) {
+        if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
+            return PackageManager.VERIFICATION_REJECT;
+        }
         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                 android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
                 DEFAULT_VERIFICATION_RESPONSE);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 9ef7410..fb7ccc7 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -735,7 +735,8 @@
                 }
             }
 
-            if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
+            if ((calling != null || mPersistentVrModeEnabled)
+                    && !Objects.equals(calling, mCurrentVrModeComponent)) {
                 sendUpdatedCaller = true;
             }
             mCurrentVrModeComponent = calling;