Merge "Add AsyncTask to compiled classes" into oc-dr1-dev
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 807b4e7..7bbed29 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -568,10 +568,6 @@
          during voice calls -->
     <bool translatable="false" name="config_wifi_framework_enable_voice_call_sar_tx_power_limit">false</bool>
 
-    <!-- Integer indicating the value that framework needs to set the tx power to for meeting SAR requirements
-         during voice calls -->
-    <integer translatable="false" name="config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm">0</integer>
-
     <!-- Wifi driver supports batched scan -->
     <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ba5bbfe..115dc9f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -313,7 +313,6 @@
   <java-symbol type="bool" name="config_wifi_framework_enable_associated_network_selection" />
   <java-symbol type="bool" name="config_wifi_only_link_same_credential_configurations" />
   <java-symbol type="bool" name="config_wifi_framework_enable_voice_call_sar_tx_power_limit" />
-  <java-symbol type="integer" name="config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm" />
   <java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" />
   <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
   <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 0834d04..28c5276 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -104,11 +104,11 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"ОС Android"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Видалені програми"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Видалені програми та користувачі"</string>
-    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Прив\'язка USB"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-модем"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Порт. точка дост."</string>
-    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Прив\'язка Bluetooth"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-модем"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Прив\'язка"</string>
-    <string name="tether_settings_title_all" msgid="8356136101061143841">"Режим модема"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Точка доступу й модем"</string>
     <string name="managed_user_title" msgid="8109605045406748842">"Усі робочі додатки"</string>
     <string name="user_guest" msgid="8475274842845401871">"Гість"</string>
     <string name="unknown" msgid="1592123443519355854">"Невідомо"</string>
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 63f80ae..1fd239b 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -40,7 +40,6 @@
         android:background="@color/qs_detail_progress_track"
         android:src="@drawable/indeterminate_anim"
         android:scaleType="fitXY"
-        android:translationY="16dp"
         />
 
     <com.android.systemui.qs.NonInterceptingScrollView
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 34aa6d0..3c86c87 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -267,14 +267,15 @@
     <!-- Doze: alpha to apply to small icons when dozing -->
     <integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
 
-    <!-- Doze: the brightness value to use for the lower brightness AOD mode -->
-    <integer name="config_doze_aod_brightness_low">5</integer>
-
-    <!-- Doze: the brightness value to use for the higher brightness AOD mode -->
-    <integer name="config_doze_aod_brightness_high">27</integer>
-
-    <!-- Doze: the brightness value to use for the sunlight AOD mode -->
-    <integer name="config_doze_aod_brightness_sunlight">28</integer>
+    <!-- Doze: Table that translates sensor values from the doze_brightness_sensor_type sensor
+               to brightness values; -1 means keeping the current brightness. -->
+    <integer-array name="config_doze_brightness_sensor_to_brightness">
+        <item>-1</item> <!-- 0: OFF -->
+        <item>2</item> <!-- 1: NIGHT -->
+        <item>5</item> <!-- 2: LOW -->
+        <item>27</item> <!-- 3: HIGH -->
+        <item>28</item> <!-- 4: SUN -->
+    </integer-array>
 
     <!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
     <bool name="doze_double_tap_reports_touch_coordinates">false</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 5237244..0c067ff 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -40,6 +40,8 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.volume.VolumeDialogControllerImpl;
 
+import java.util.function.Consumer;
+
 /**
  * Class factory to provide customizable SystemUI components.
  */
@@ -84,8 +86,10 @@
 
     public ScrimController createScrimController(LightBarController lightBarController,
             ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
-            LockscreenWallpaper lockscreenWallpaper) {
-        return new ScrimController(lightBarController, scrimBehind, scrimInFront, headsUpScrim);
+            LockscreenWallpaper lockscreenWallpaper,
+            Consumer<Boolean> scrimVisibleListener) {
+        return new ScrimController(lightBarController, scrimBehind, scrimInFront, headsUpScrim,
+                scrimVisibleListener);
     }
 
     public NotificationIconAreaController createNotificationIconAreaController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index ed4b131..32baf94 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -35,12 +35,9 @@
     private final Handler mHandler;
     private final SensorManager mSensorManager;
     private final Sensor mLightSensor;
+    private final int[] mSensorToBrightness;
     private boolean mRegistered;
 
-    private final int mHighBrightness;
-    private final int mLowBrightness;
-    private final int mSunlightBrightness;
-
     public DozeScreenBrightness(Context context, DozeMachine.Service service,
             SensorManager sensorManager, Sensor lightSensor, Handler handler) {
         mContext = context;
@@ -49,12 +46,8 @@
         mLightSensor = lightSensor;
         mHandler = handler;
 
-        mLowBrightness = context.getResources().getInteger(
-                R.integer.config_doze_aod_brightness_low);
-        mHighBrightness = context.getResources().getInteger(
-                R.integer.config_doze_aod_brightness_high);
-        mSunlightBrightness = context.getResources().getInteger(
-                R.integer.config_doze_aod_brightness_sunlight);
+        mSensorToBrightness = context.getResources().getIntArray(
+                R.array.config_doze_brightness_sensor_to_brightness);
     }
 
     @Override
@@ -81,21 +74,18 @@
     @Override
     public void onSensorChanged(SensorEvent event) {
         if (mRegistered) {
-            mDozeService.setDozeScreenBrightness(computeBrightness((int) event.values[0]));
+            int brightness = computeBrightness((int) event.values[0]);
+            if (brightness > 0) {
+                mDozeService.setDozeScreenBrightness(brightness);
+            }
         }
     }
 
     private int computeBrightness(int sensorValue) {
-        // The sensor reports 0 for off, 1 for low brightness, 2 for high brightness, and 3 for
-        // sunlight. We currently use DozeScreenState for screen off, so we treat off as low
-        // brightness.
-        if (sensorValue >= 3) {
-            return mSunlightBrightness;
-        } else if (sensorValue == 2) {
-            return mHighBrightness;
-        } else {
-            return mLowBrightness;
+        if (sensorValue < 0 || sensorValue >= mSensorToBrightness.length) {
+            return -1;
         }
+        return mSensorToBrightness[sensorValue];
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index c691498..12fccda 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -83,7 +83,7 @@
     @Override
     protected void handleClick() {
         // Secondary clicks are header clicks, just toggle.
-        final boolean isEnabled = (Boolean)mState.value;
+        final boolean isEnabled = mState.value;
         mController.setBluetoothEnabled(!isEnabled);
     }
 
@@ -100,6 +100,9 @@
             return;
         }
         showDetail(true);
+        if (!mState.value) {
+            mController.setBluetoothEnabled(true);
+        }
     }
 
     @Override
@@ -179,6 +182,7 @@
             refreshState();
             if (isShowingDetail()) {
                 mDetailAdapter.updateItems();
+                fireToggleStateChanged(mDetailAdapter.getToggleState());
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 6c31cef..5938749 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -33,6 +33,7 @@
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.service.quicksettings.Tile;
+import android.util.Log;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,6 +55,7 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeController.Callback;
 import com.android.systemui.volume.ZenModePanel;
 
 /** Quick settings tile: Do not disturb **/
@@ -147,7 +149,22 @@
                     Toast.LENGTH_LONG).show();
             return;
         }
-        showDetail(true);
+        if (!mState.value) {
+            // Because of the complexity of the zen panel, it needs to be shown after
+            // we turn on zen below.
+            mController.addCallback(new ZenModeController.Callback() {
+                @Override
+                public void onZenChanged(int zen) {
+                    mController.removeCallback(this);
+                    showDetail(true);
+                }
+            });
+            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
+                    Global.ZEN_MODE_ALARMS);
+            mController.setZen(zen, null, TAG);
+        } else {
+            showDetail(true);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index d9984f7..61c9e4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -127,6 +127,9 @@
             return;
         }
         showDetail(true);
+        if (!mState.value) {
+            mController.setWifiEnabled(true);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 05d47ec..f5dc038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -23,11 +23,12 @@
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -54,9 +55,16 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.text.NumberFormat;
+import java.util.Arrays;
 
 public class StatusBarIconView extends AnimatedImageView {
     public static final int NO_COLOR = 0;
+
+    /**
+     * Multiply alpha values with (1+DARK_ALPHA_BOOST) when dozing. The chosen value boosts
+     * everything above 30% to 50%, making it appear on 1bit color depths.
+     */
+    private static final float DARK_ALPHA_BOOST = 0.67f;
     private final int ANIMATION_DURATION_FAST = 100;
 
     public static final int STATE_ICON = 0;
@@ -131,6 +139,8 @@
     private final NotificationIconDozeHelper mDozer;
     private int mContrastedDrawableColor;
     private int mCachedContrastBackgroundColor = NO_COLOR;
+    private float[] mMatrix;
+    private ColorMatrixColorFilter mMatrixColorFilter;
 
     public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
         this(context, slot, sbn, false);
@@ -544,14 +554,33 @@
 
     private void updateIconColor() {
         if (mCurrentSetColor != NO_COLOR) {
-            setImageTintList(ColorStateList.valueOf(NotificationUtils.interpolateColors(
-                    mCurrentSetColor, Color.WHITE, mDarkAmount)));
+            if (mMatrixColorFilter == null) {
+                mMatrix = new float[4 * 5];
+                mMatrixColorFilter = new ColorMatrixColorFilter(mMatrix);
+            }
+            int color = NotificationUtils.interpolateColors(
+                    mCurrentSetColor, Color.WHITE, mDarkAmount);
+            updateTintMatrix(mMatrix, color, DARK_ALPHA_BOOST * mDarkAmount);
+            mMatrixColorFilter.setColorMatrixArray(mMatrix);
+            setColorFilter(mMatrixColorFilter);
+            invalidate();  // setColorFilter only invalidates if the filter instance changed.
         } else {
-            setImageTintList(null);
             mDozer.updateGrayscale(this, mDarkAmount);
         }
     }
 
+    /**
+     * Updates {@param array} such that it represents a matrix that changes RGB to {@param color}
+     * and multiplies A with 1+{@param alphaBoost}.
+     */
+    private static void updateTintMatrix(float[] array, int color, float alphaBoost) {
+        Arrays.fill(array, 0);
+        array[4] = Color.red(color);
+        array[9] = Color.green(color);
+        array[14] = Color.blue(color);
+        array[18] = 1 + alphaBoost;
+    }
+
     public void setIconColor(int iconColor, boolean animate) {
         if (mIconColor != iconColor) {
             mIconColor = iconColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 62d4b73..eabf07b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -25,6 +25,7 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Trace;
 import android.util.MathUtils;
 import android.view.View;
 import android.view.ViewGroup;
@@ -46,6 +47,8 @@
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.stack.ViewState;
 
+import java.util.function.Consumer;
+
 /**
  * Controls both the scrim behind the notifications and in front of the notifications (when a
  * security method gets shown).
@@ -125,12 +128,16 @@
     private boolean mWakingUpFromAodInProgress;
     /** Wake up from AOD transition is animating; need to reset when animation finishes */
     private boolean mWakingUpFromAodAnimationRunning;
+    private boolean mScrimsVisble;
+    private final Consumer<Boolean> mScrimVisibleListener;
 
     public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
-            ScrimView scrimInFront, View headsUpScrim) {
+            ScrimView scrimInFront, View headsUpScrim,
+            Consumer<Boolean> scrimVisibleListener) {
         mScrimBehind = scrimBehind;
         mScrimInFront = scrimInFront;
         mHeadsUpScrim = headsUpScrim;
+        mScrimVisibleListener = scrimVisibleListener;
         final Context context = scrimBehind.getContext();
         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
@@ -192,7 +199,11 @@
         scheduleUpdate();
     }
 
+    /** Prepares the wakeUpFromAod animation (while turning on screen); Forces black scrims. */
     public void prepareWakeUpFromAod() {
+        if (mWakingUpFromAodInProgress) {
+            return;
+        }
         mWakingUpFromAodInProgress = true;
         mWakingUpFromAodStarting = true;
         mAnimateChange = false;
@@ -200,10 +211,12 @@
         onPreDraw();
     }
 
+    /** Starts the wakeUpFromAod animation (once screen is on); animate to transparent scrims. */
     public void wakeUpFromAod() {
         if (mWakeAndUnlocking || mAnimateKeyguardFadingOut) {
             // Wake and unlocking has a separate transition that must not be interfered with.
             mWakingUpFromAodStarting = false;
+            mWakingUpFromAodInProgress = false;
             return;
         }
         if (mWakingUpFromAodStarting) {
@@ -218,6 +231,7 @@
         mWakeAndUnlocking = true;
         mAnimatingDozeUnlock = true;
         mWakingUpFromAodStarting = false;
+        mWakingUpFromAodInProgress = false;
         scheduleUpdate();
     }
 
@@ -328,7 +342,6 @@
     }
 
     protected void updateScrims() {
-
         // Make sure we have the right gradients
         if (mNeedsDrawableColorUpdate) {
             mNeedsDrawableColorUpdate = false;
@@ -359,13 +372,24 @@
                 setScrimInFrontAlpha(1f);
                 setScrimBehindAlpha(0f);
             }
-        } else if (!mKeyguardShowing && !mBouncerShowing) {
+        } else if (!mKeyguardShowing && !mBouncerShowing && !mWakingUpFromAodStarting) {
             updateScrimNormal();
             setScrimInFrontAlpha(0);
         } else {
             updateScrimKeyguard();
         }
         mAnimateChange = false;
+        dispatchScrimsVisible();
+    }
+
+    private void dispatchScrimsVisible() {
+        boolean scrimsVisible = mScrimBehind.getViewAlpha() > 0 || mScrimInFront.getViewAlpha() > 0;
+
+        if (mScrimsVisble != scrimsVisible) {
+            mScrimsVisble = scrimsVisible;
+
+            mScrimVisibleListener.accept(scrimsVisible);
+        }
     }
 
     private void updateScrimKeyguard() {
@@ -457,6 +481,10 @@
             alpha = Math.max(0, Math.min(1.0f, alpha));
             scrimView.setViewAlpha(alpha);
 
+            Trace.traceCounter(Trace.TRACE_TAG_APP,
+                    scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
+                    (int) (alpha * 255));
+
             int dozeTint = Color.TRANSPARENT;
 
             boolean dozing = mAnimatingDozeUnlock || mDozing;
@@ -464,6 +492,10 @@
             if (dozing || frontScrimDozing && scrim == mScrimInFront) {
                 dozeTint = Color.BLACK;
             }
+            Trace.traceCounter(Trace.TRACE_TAG_APP,
+                    scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
+                    dozeTint == Color.BLACK ? 1 : 0);
+
             scrimView.setTint(dozeTint);
         } else {
             scrim.setAlpha(alpha1);
@@ -477,6 +509,7 @@
             float alpha = (float) animation.getAnimatedValue();
             setCurrentScrimAlpha(scrim, alpha);
             updateScrimColor(scrim);
+            dispatchScrimsVisible();
         });
         anim.setInterpolator(getInterpolator());
         anim.setStartDelay(mAnimationDelay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 136c158..0b57e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1132,7 +1132,12 @@
         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
         View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
         mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
-                scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper);
+                scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper,
+                scrimsVisible -> {
+                    if (mStatusBarWindowManager != null) {
+                        mStatusBarWindowManager.setScrimsVisible(scrimsVisible);
+                    }
+                });
         if (mScrimSrcModeEnabled) {
             Runnable runnable = new Runnable() {
                 @Override
@@ -5171,6 +5176,9 @@
             mStackScroller.setAnimationsEnabled(true);
             mVisualStabilityManager.setScreenOn(true);
             mNotificationPanel.setTouchDisabled(false);
+
+            maybePrepareWakeUpFromAod();
+
             mDozeServiceHost.stopDozing();
             updateVisibleToUser();
             updateIsKeyguard();
@@ -5183,11 +5191,7 @@
             mFalsingManager.onScreenTurningOn();
             mNotificationPanel.onScreenTurningOn();
 
-            int wakefulness = mWakefulnessLifecycle.getWakefulness();
-            if (mDozing && (wakefulness == WAKEFULNESS_WAKING
-                    || wakefulness == WAKEFULNESS_ASLEEP) && !isPulsing()) {
-                mScrimController.prepareWakeUpFromAod();
-            }
+            maybePrepareWakeUpFromAod();
 
             if (mLaunchCameraOnScreenTurningOn) {
                 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
@@ -5216,6 +5220,14 @@
         return mWakefulnessLifecycle.getWakefulness();
     }
 
+    private void maybePrepareWakeUpFromAod() {
+        int wakefulness = mWakefulnessLifecycle.getWakefulness();
+        if (mDozing && (wakefulness == WAKEFULNESS_WAKING
+                || wakefulness == WAKEFULNESS_ASLEEP) && !isPulsing()) {
+            mScrimController.prepareWakeUpFromAod();
+        }
+    }
+
     private void vibrateForCameraGesture() {
         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
         mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 836b2ef..d886508 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -186,7 +186,7 @@
     private boolean isExpanded(State state) {
         return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
                 || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
-                || state.headsUpShowing);
+                || state.headsUpShowing || state.scrimsVisible);
     }
 
     private void applyFitsSystemWindows(State state) {
@@ -325,6 +325,11 @@
         apply(mCurrentState);
     }
 
+    public void setScrimsVisible(boolean scrimsVisible) {
+        mCurrentState.scrimsVisible = scrimsVisible;
+        apply(mCurrentState);
+    }
+
     public void setHeadsUpShowing(boolean showing) {
         mCurrentState.headsUpShowing = showing;
         apply(mCurrentState);
@@ -426,6 +431,7 @@
         boolean remoteInputActive;
         boolean forcePluginOpen;
         boolean dozing;
+        boolean scrimsVisible;
 
         private boolean isKeyguardShowingAndNotOccluded() {
             return keyguardShowing && !keyguardOccluded;
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 703e50a..0d935db 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -142,6 +142,18 @@
             extraInfo = null;
         }
 
+        // Clear any previous notification with lower priority, otherwise return. http://b/63676954.
+        // A new SIGN_IN notification with a new intent should override any existing one.
+        final int previousEventId = mNotificationTypeMap.get(id);
+        final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
+        if (priority(previousNotifyType) > priority(notifyType)) {
+            Slog.d(TAG, String.format(
+                    "ignoring notification %s for network %s with existing notification %s",
+                    notifyType, id, previousNotifyType));
+            return;
+        }
+        clearNotification(id);
+
         if (DBG) {
             Slog.d(TAG, String.format(
                     "showNotification tag=%s event=%s transport=%s extraInfo=%s highPrioriy=%s",
@@ -274,4 +286,22 @@
         NotificationType t = NotificationType.getFromId(eventId);
         return (t != null) ? t.name() : "UNKNOWN";
     }
+
+    private static int priority(NotificationType t) {
+        if (t == null) {
+            return 0;
+        }
+        switch (t) {
+            case SIGN_IN:
+                return 4;
+            case NO_INTERNET:
+                return 3;
+            case NETWORK_SWITCH:
+                return 2;
+            case LOST_INTERNET:
+                return 1;
+            default:
+                return 0;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5bd5e21..2caac7a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6003,9 +6003,9 @@
             return;
         }
 
-        if (!displayContent.isReady() || !mPolicy.isScreenOn()) {
-            // No need to freeze the screen before the display is ready, system is ready, or if
-            // the screen is off.
+        if (!displayContent.isReady() || !mPolicy.isScreenOn() || !okToAnimate()) {
+            // No need to freeze the screen before the display is ready,  if the screen is off,
+            // or we can't currently animate.
             return;
         }
 
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index f201bc7..911347c 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -16,6 +16,16 @@
 
 package com.android.server.connectivity;
 
+import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Context;
@@ -37,15 +47,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 public class NetworkNotificationManagerTest extends TestCase {
 
     static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
@@ -140,4 +141,47 @@
 
         verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
     }
+
+    @SmallTest
+    public void testDuplicatedNotificationsNoInternetThenSignIn() {
+        final int id = 101;
+        final String tag = NetworkNotificationManager.tagFor(id);
+
+        // Show first NO_INTERNET
+        mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
+        verify(mNotificationManager, times(1))
+                .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
+
+        // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
+        mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
+        verify(mNotificationManager, times(1))
+                .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
+        verify(mNotificationManager, times(1))
+                .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
+
+        // Network disconnects
+        mManager.clearNotification(id);
+        verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
+    }
+
+    @SmallTest
+    public void testDuplicatedNotificationsSignInThenNoInternet() {
+        final int id = 101;
+        final String tag = NetworkNotificationManager.tagFor(id);
+
+        // Show first SIGN_IN
+        mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
+        verify(mNotificationManager, times(1))
+                .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
+        reset(mNotificationManager);
+
+        // NO_INTERNET arrives after, but is ignored.
+        mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
+        verify(mNotificationManager, never()).cancelAsUser(any(), anyInt(), any());
+        verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+
+        // Network disconnects
+        mManager.clearNotification(id);
+        verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
+    }
 }