Merge "Fix issue when adding existing connections via remote connection services." into sc-dev am: 5f54351908

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15113691

Change-Id: Ib5f229b2b23b633a510fe5cad7b9ce3cde3450d8
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index b2b66c2..3534624 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -71,7 +71,7 @@
         "libui",
         "libjnigraphics",
         "libEGL",
-        "libGLESv1_CM",
+        "libGLESv2",
         "libgui",
     ],
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3109c5c..98e447c 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -52,9 +52,8 @@
 #include <gui/DisplayEventReceiver.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 #include <EGL/eglext.h>
 
 #include "BootAnimation.h"
@@ -108,6 +107,82 @@
 static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
 static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
 static constexpr size_t TEXT_POS_LEN_MAX = 16;
+static const int DYNAMIC_COLOR_COUNT = 4;
+static const char U_TEXTURE[] = "uTexture";
+static const char U_FADE[] = "uFade";
+static const char U_CROP_AREA[] = "uCropArea";
+static const char U_START_COLOR_PREFIX[] = "uStartColor";
+static const char U_END_COLOR_PREFIX[] = "uEndColor";
+static const char U_COLOR_PROGRESS[] = "uColorProgress";
+static const char A_UV[] = "aUv";
+static const char A_POSITION[] = "aPosition";
+static const char VERTEX_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    attribute vec4 aPosition;
+    attribute highp vec2 aUv;
+    varying highp vec2 vUv;
+    void main() {
+        gl_Position = aPosition;
+        vUv = aUv;
+    })";
+static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    uniform sampler2D uTexture;
+    uniform float uFade;
+    uniform float uColorProgress;
+    uniform vec4 uStartColor0;
+    uniform vec4 uStartColor1;
+    uniform vec4 uStartColor2;
+    uniform vec4 uStartColor3;
+    uniform vec4 uEndColor0;
+    uniform vec4 uEndColor1;
+    uniform vec4 uEndColor2;
+    uniform vec4 uEndColor3;
+    varying highp vec2 vUv;
+    void main() {
+        vec4 mask = texture2D(uTexture, vUv);
+        vec4 color = mask.r * mix(uStartColor0, uEndColor0, uColorProgress)
+            + mask.g * mix(uStartColor1, uEndColor1, uColorProgress)
+            + mask.b * mix(uStartColor2, uEndColor2, uColorProgress)
+            + mask.a * mix(uStartColor3, uEndColor3, uColorProgress);
+        gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
+    })";
+static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    uniform sampler2D uTexture;
+    uniform float uFade;
+    varying highp vec2 vUv;
+    void main() {
+        vec4 color = texture2D(uTexture, vUv);
+        gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
+    })";
+static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    uniform sampler2D uTexture;
+    uniform vec4 uCropArea;
+    varying highp vec2 vUv;
+    void main() {
+        vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x),
+                       mix(uCropArea.y, uCropArea.w, vUv.y));
+        gl_FragColor = texture2D(uTexture, uv);
+    })";
+
+static GLfloat quadPositions[] = {
+    -0.5f, -0.5f,
+    +0.5f, -0.5f,
+    +0.5f, +0.5f,
+    +0.5f, +0.5f,
+    -0.5f, +0.5f,
+    -0.5f, -0.5f
+};
+static GLfloat quadUVs[] = {
+    0.0f, 1.0f,
+    1.0f, 1.0f,
+    1.0f, 0.0f,
+    1.0f, 0.0f,
+    0.0f, 0.0f,
+    0.0f, 1.0f
+};
 
 // ---------------------------------------------------------------------------
 
@@ -163,7 +238,8 @@
     requestExit();
 }
 
-static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) {
+static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo,
+    bool premultiplyAlpha) {
     AImageDecoder* decoder = nullptr;
     AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
     if (!decoder) {
@@ -177,6 +253,10 @@
     outInfo->stride = AImageDecoder_getMinimumStride(decoder);
     outInfo->flags = 0;
 
+    if (!premultiplyAlpha) {
+        AImageDecoder_setUnpremultipliedRequired(decoder, true);
+    }
+
     const size_t size = outInfo->stride * outInfo->height;
     void* pixels = malloc(size);
     int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
@@ -190,13 +270,14 @@
 }
 
 status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
-        const char* name) {
+        const char* name, bool premultiplyAlpha) {
     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
     if (asset == nullptr)
         return NO_INIT;
 
     AndroidBitmapInfo bitmapInfo;
-    void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo);
+    void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo,
+        premultiplyAlpha);
     auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
 
     asset->close();
@@ -209,7 +290,6 @@
     const int w = bitmapInfo.width;
     const int h = bitmapInfo.height;
 
-    GLint crop[4] = { 0, h, w, -h };
     texture->w = w;
     texture->h = h;
 
@@ -237,18 +317,19 @@
             break;
     }
 
-    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     return NO_ERROR;
 }
 
-status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
+status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
+    bool premultiplyAlpha) {
     AndroidBitmapInfo bitmapInfo;
-    void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo);
+    void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
+        premultiplyAlpha);
     auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
 
     // FileMap memory is never released until application exit.
@@ -263,7 +344,6 @@
     const int w = bitmapInfo.width;
     const int h = bitmapInfo.height;
 
-    GLint crop[4] = { 0, h, w, -h };
     int tw = 1 << (31 - __builtin_clz(w));
     int th = 1 << (31 - __builtin_clz(h));
     if (tw < w) tw <<= 1;
@@ -297,7 +377,10 @@
             break;
     }
 
-    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     *width = w;
     *height = h;
@@ -470,7 +553,9 @@
     eglInitialize(display, nullptr, nullptr);
     EGLConfig config = getEglConfig(display);
     EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
-    EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
+    // Initialize egl context with client version number 2.0.
+    EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+    EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
     EGLint w, h;
     eglQuerySurface(display, surface, EGL_WIDTH, &w);
     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@@ -503,11 +588,6 @@
 void BootAnimation::projectSceneToWindow() {
     glViewport(0, 0, mWidth, mHeight);
     glScissor(0, 0, mWidth, mHeight);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
 }
 
 void BootAnimation::resizeSurface(int newWidth, int newHeight) {
@@ -600,8 +680,71 @@
     }
 }
 
+GLuint compileShader(GLenum shaderType, const GLchar *source) {
+    GLuint shader = glCreateShader(shaderType);
+    glShaderSource(shader, 1, &source, 0);
+    glCompileShader(shader);
+    GLint isCompiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+    if (isCompiled == GL_FALSE) {
+        SLOGE("Compile shader failed. Shader type: %d", shaderType);
+        return 0;
+    }
+    return shader;
+}
+
+GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
+    GLuint program = glCreateProgram();
+    glAttachShader(program, vertexShader);
+    glAttachShader(program, fragmentShader);
+    glLinkProgram(program);
+    GLint isLinked = 0;
+    glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
+    if (isLinked == GL_FALSE) {
+        SLOGE("Linking shader failed. Shader handles: vert %d, frag %d",
+            vertexShader, fragmentShader);
+        return 0;
+    }
+    return program;
+}
+
+void BootAnimation::initShaders() {
+    bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
+    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
+    GLuint imageFragmentShader =
+        compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled
+            ? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE
+            : (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
+    GLuint textFragmentShader =
+        compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
+
+    // Initialize image shader.
+    mImageShader = linkShader(vertexShader, imageFragmentShader);
+    GLint positionLocation = glGetAttribLocation(mImageShader, A_POSITION);
+    GLint uvLocation = glGetAttribLocation(mImageShader, A_UV);
+    mImageTextureLocation = glGetUniformLocation(mImageShader, U_TEXTURE);
+    mImageFadeLocation = glGetUniformLocation(mImageShader, U_FADE);
+    glEnableVertexAttribArray(positionLocation);
+    glVertexAttribPointer(positionLocation, 2,  GL_FLOAT, GL_FALSE, 0, quadPositions);
+    glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
+    glEnableVertexAttribArray(uvLocation);
+
+    // Initialize text shader.
+    mTextShader = linkShader(vertexShader, textFragmentShader);
+    positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
+    uvLocation = glGetAttribLocation(mTextShader, A_UV);
+    mTextTextureLocation = glGetUniformLocation(mTextShader, U_TEXTURE);
+    mTextCropAreaLocation = glGetUniformLocation(mTextShader, U_CROP_AREA);
+    glEnableVertexAttribArray(positionLocation);
+    glVertexAttribPointer(positionLocation, 2,  GL_FLOAT, GL_FALSE, 0, quadPositions);
+    glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
+    glEnableVertexAttribArray(uvLocation);
+}
+
 bool BootAnimation::threadLoop() {
     bool result;
+    initShaders();
+
     // We have no bootanimation file, so we use the stock android logo
     // animation.
     if (mZipFileName.isEmpty()) {
@@ -623,6 +766,8 @@
 }
 
 bool BootAnimation::android() {
+    glActiveTexture(GL_TEXTURE0);
+
     SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
             elapsedRealtime());
     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
@@ -631,19 +776,14 @@
     mCallbacks->init({});
 
     // clear screen
-    glShadeModel(GL_FLAT);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
     glClearColor(0,0,0,1);
     glClear(GL_COLOR_BUFFER_BIT);
     eglSwapBuffers(mDisplay, mSurface);
 
-    glEnable(GL_TEXTURE_2D);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
     // Blend state
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
     const nsecs_t startTime = systemTime();
     do {
@@ -666,12 +806,12 @@
         glEnable(GL_SCISSOR_TEST);
         glDisable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
-        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
-        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
+        drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h);
+        drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
 
         glEnable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
-        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
+        drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
 
         EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
         if (res == EGL_FALSE)
@@ -766,6 +906,20 @@
     return true;
 }
 
+// Parse a color represented as a signed decimal int string.
+// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
+// If the input color string is empty, set color with values in defaultColor.
+static void parseColorDecimalString(const std::string& colorString,
+    float color[3], float defaultColor[3]) {
+    if (colorString == "") {
+        memcpy(color, defaultColor, sizeof(float) * 3);
+        return;
+    }
+    int colorInt = atoi(colorString.c_str());
+    color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
+    color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
+    color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
+}
 
 static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
     ZipEntryRO entry = zip->findEntryByName(name);
@@ -798,10 +952,10 @@
 
         status = initTexture(font->map, &font->texture.w, &font->texture.h);
 
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     } else if (fallback != nullptr) {
         status = initTexture(&font->texture, mAssets, fallback);
     } else {
@@ -816,40 +970,11 @@
     return status;
 }
 
-void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth,
-                              const int frameHeight, const Animation::Part& part,
-                              const int fadedFramesCount) {
-    glEnable(GL_BLEND);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glDisable(GL_TEXTURE_2D);
-    // avoid creating a hole due to mixing result alpha with GL_REPLACE texture
-    glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
-
-    const float alpha = static_cast<float>(fadedFramesCount) / part.framesToFadeCount;
-    glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha);
-
-    const float frameStartX = static_cast<float>(frameLeft);
-    const float frameStartY = static_cast<float>(frameBottom);
-    const float frameEndX = frameStartX + frameWidth;
-    const float frameEndY = frameStartY + frameHeight;
-    const GLfloat frameRect[] = {
-        frameStartX, frameStartY,
-        frameEndX,   frameStartY,
-        frameEndX,   frameEndY,
-        frameStartX, frameEndY
-    };
-    glVertexPointer(2, GL_FLOAT, 0, frameRect);
-    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glEnable(GL_TEXTURE_2D);
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glDisable(GL_BLEND);
-}
-
 void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
     glEnable(GL_BLEND);  // Allow us to draw on top of the animation
     glBindTexture(GL_TEXTURE_2D, font.texture.name);
+    glUseProgram(mTextShader);
+    glUniform1i(mTextTextureLocation, 0);
 
     const int len = strlen(str);
     const int strWidth = font.char_width * len;
@@ -865,8 +990,6 @@
         *y = mHeight + *y - font.char_height;
     }
 
-    int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
-
     for (int i = 0; i < len; i++) {
         char c = str[i];
 
@@ -878,13 +1001,13 @@
         const int charPos = (c - FONT_BEGIN_CHAR);  // Position in the list of valid characters
         const int row = charPos / FONT_NUM_COLS;
         const int col = charPos % FONT_NUM_COLS;
-        cropRect[0] = col * font.char_width;  // Left of column
-        cropRect[1] = row * font.char_height * 2; // Top of row
-        // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
-        cropRect[1] += bold ? 2 * font.char_height : font.char_height;
-        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
-
-        glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
+        // Bold fonts are expected in the second half of each row.
+        float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS;
+        float u0 = ((float)col) / FONT_NUM_COLS;
+        float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
+        float u1 = u0 + 1.0f / FONT_NUM_COLS;
+        glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
+        drawTexturedQuad(*x, *y, font.char_width, font.char_height);
 
         *x += font.char_width;
     }
@@ -938,6 +1061,8 @@
         return false;
     }
     char const* s = desString.string();
+    std::string dynamicColoringPartName = "";
+    bool postDynamicColoring = false;
 
     // Parse the description file
     for (;;) {
@@ -956,7 +1081,13 @@
         char color[7] = "000000"; // default to black if unspecified
         char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
         char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
+        char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
         char pathType;
+        // start colors default to black if unspecified
+        char start_color_0[7] = "000000";
+        char start_color_1[7] = "000000";
+        char start_color_2[7] = "000000";
+        char start_color_3[7] = "000000";
 
         int nextReadPos;
 
@@ -971,6 +1102,15 @@
             } else {
               animation.progressEnabled = false;
             }
+        } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s",
+            dynamicColoringPartNameBuffer,
+            start_color_0, start_color_1, start_color_2, start_color_3)) {
+            animation.dynamicColoringEnabled = true;
+            parseColor(start_color_0, animation.startColors[0]);
+            parseColor(start_color_1, animation.startColors[1]);
+            parseColor(start_color_2, animation.startColors[2]);
+            parseColor(start_color_3, animation.startColors[3]);
+            dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
         } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
                           &pathType, &count, &pause, path, &nextReadPos) >= 4) {
             if (pathType == 'f') {
@@ -983,6 +1123,16 @@
             //       "clockPos1=%s, clockPos2=%s",
             //       pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
             Animation::Part part;
+            if (path == dynamicColoringPartName) {
+                // Part is specified to use dynamic coloring.
+                part.useDynamicColoring = true;
+                part.postDynamicColoring = false;
+                postDynamicColoring = true;
+            } else {
+                // Part does not use dynamic coloring.
+                part.useDynamicColoring = false;
+                part.postDynamicColoring =  postDynamicColoring;
+            }
             part.playUntilComplete = pathType == 'c';
             part.framesToFadeCount = framesToFadeCount;
             part.count = count;
@@ -1166,19 +1316,16 @@
 
     // Blend required to draw time on top of animation frames.
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glShadeModel(GL_FLAT);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
     glDisable(GL_BLEND);
 
-    glBindTexture(GL_TEXTURE_2D, 0);
     glEnable(GL_TEXTURE_2D);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     bool clockFontInitialized = false;
     if (mClockEnabled) {
         clockFontInitialized =
@@ -1193,6 +1340,10 @@
         mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
     }
 
+    if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) {
+        initDynamicColors();
+    }
+
     playAnimation(*mAnimation);
 
     if (mTimeCheckThread != nullptr) {
@@ -1218,6 +1369,55 @@
         (lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
 }
 
+// Linear mapping from range <a1, a2> to range <b1, b2>
+float mapLinear(float x, float a1, float a2, float b1, float b2) {
+    return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
+}
+
+void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
+    // Map coordinates from screen space to world space.
+    float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
+    float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
+    float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1);
+    float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1);
+    // Update quad vertex positions.
+    quadPositions[0] = x0;
+    quadPositions[1] = y0;
+    quadPositions[2] = x1;
+    quadPositions[3] = y0;
+    quadPositions[4] = x1;
+    quadPositions[5] = y1;
+    quadPositions[6] = x1;
+    quadPositions[7] = y1;
+    quadPositions[8] = x0;
+    quadPositions[9] = y1;
+    quadPositions[10] = x0;
+    quadPositions[11] = y0;
+    glDrawArrays(GL_TRIANGLES, 0,
+        sizeof(quadPositions) / sizeof(quadPositions[0]) / 2);
+}
+
+void BootAnimation::initDynamicColors() {
+    for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+        parseColorDecimalString(
+            android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
+            mAnimation->endColors[i], mAnimation->startColors[i]);
+    }
+    glUseProgram(mImageShader);
+    SLOGI("[BootAnimation] Dynamically coloring boot animation.");
+    for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+        float *startColor = mAnimation->startColors[i];
+        float *endColor = mAnimation->endColors[i];
+        glUniform4f(glGetUniformLocation(mImageShader,
+            (U_START_COLOR_PREFIX + std::to_string(i)).c_str()),
+            startColor[0], startColor[1], startColor[2], 1 /* alpha */);
+        glUniform4f(glGetUniformLocation(mImageShader,
+            (U_END_COLOR_PREFIX + std::to_string(i)).c_str()),
+            endColor[0], endColor[1], endColor[2], 1 /* alpha */);
+    }
+    mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS);
+}
+
 bool BootAnimation::playAnimation(const Animation& animation) {
     const size_t pcount = animation.parts.size();
     nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -1230,7 +1430,6 @@
     for (size_t i=0 ; i<pcount ; i++) {
         const Animation::Part& part(animation.parts[i]);
         const size_t fcount = part.frames.size();
-        glBindTexture(GL_TEXTURE_2D, 0);
 
         // Handle animation package
         if (part.animation != nullptr) {
@@ -1261,6 +1460,14 @@
             for (size_t j=0 ; j<fcount ; j++) {
                 if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
 
+                // Color progress is
+                // - the normalized animation progress between [0, 1] for the dynamic coloring part,
+                // - 0 for parts that come before,
+                // - 1 for parts that come after.
+                float colorProgress = part.useDynamicColoring
+                    ? (float)j / fcount
+                    : (part.postDynamicColoring ? 1 : 0);
+
                 processDisplayEvents();
 
                 const int animationX = (mWidth - animation.width) / 2;
@@ -1272,44 +1479,38 @@
                 if (r > 0) {
                     glBindTexture(GL_TEXTURE_2D, frame.tid);
                 } else {
-                    if (part.count != 1) {
-                        glGenTextures(1, &frame.tid);
-                        glBindTexture(GL_TEXTURE_2D, frame.tid);
-                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-                    }
+                    glGenTextures(1, &frame.tid);
+                    glBindTexture(GL_TEXTURE_2D, frame.tid);
                     int w, h;
-                    initTexture(frame.map, &w, &h);
+                    // Set decoding option to alpha unpremultiplied so that the R, G, B channels
+                    // of transparent pixels are preserved.
+                    initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
                 }
 
                 const int xc = animationX + frame.trimX;
                 const int yc = animationY + frame.trimY;
-                Region clearReg(Rect(mWidth, mHeight));
-                clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
-                if (!clearReg.isEmpty()) {
-                    Region::const_iterator head(clearReg.begin());
-                    Region::const_iterator tail(clearReg.end());
-                    glEnable(GL_SCISSOR_TEST);
-                    while (head != tail) {
-                        const Rect& r2(*head++);
-                        glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
-                        glClear(GL_COLOR_BUFFER_BIT);
-                    }
-                    glDisable(GL_SCISSOR_TEST);
-                }
+                glClear(GL_COLOR_BUFFER_BIT);
                 // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
                 // which is equivalent to mHeight - (yc + frame.trimHeight)
                 const int frameDrawY = mHeight - (yc + frame.trimHeight);
-                glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
 
+                float fade = 0;
                 // if the part hasn't been stopped yet then continue fading if necessary
                 if (exitPending() && part.hasFadingPhase()) {
-                    fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
-                              ++fadedFramesCount);
+                    fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount;
                     if (fadedFramesCount >= part.framesToFadeCount) {
                         fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
                     }
                 }
+                glUseProgram(mImageShader);
+                glUniform1i(mImageTextureLocation, 0);
+                glUniform1f(mImageFadeLocation, fade);
+                if (animation.dynamicColoringEnabled) {
+                    glUniform1f(mImageColorProgressLocation, colorProgress);
+                }
+                glEnable(GL_BLEND);
+                drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
+                glDisable(GL_BLEND);
 
                 if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
                     drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f8a31c6..0e29621 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -31,7 +31,7 @@
 #include <binder/IBinder.h>
 
 #include <EGL/egl.h>
-#include <GLES/gl.h>
+#include <GLES2/gl2.h>
 
 namespace android {
 
@@ -53,7 +53,7 @@
     };
 
     struct Font {
-        FileMap* map;
+        FileMap* map = nullptr;
         Texture texture;
         int char_width;
         int char_height;
@@ -62,7 +62,7 @@
     struct Animation {
         struct Frame {
             String8 name;
-            FileMap* map;
+            FileMap* map = nullptr;
             int trimX;
             int trimY;
             int trimWidth;
@@ -90,6 +90,10 @@
             uint8_t* audioData;
             int audioLength;
             Animation* animation;
+            // Controls if dynamic coloring is enabled for this part.
+            bool useDynamicColoring = false;
+            // Defines if this part is played after the dynamic coloring part.
+            bool postDynamicColoring = false;
 
             bool hasFadingPhase() const {
                 return !playUntilComplete && framesToFadeCount > 0;
@@ -105,6 +109,10 @@
         ZipFileRO* zip;
         Font clockFont;
         Font progressFont;
+         // Controls if dynamic coloring is enabled for the whole animation.
+        bool dynamicColoringEnabled = false;
+        float startColors[4][3]; // Start colors of dynamic color transition.
+        float endColors[4][3];   // End colors of dynamic color transition.
     };
 
     // All callbacks will be called from this class's internal thread.
@@ -163,9 +171,12 @@
     int displayEventCallback(int fd, int events, void* data);
     void processDisplayEvents();
 
-    status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
-    status_t initTexture(FileMap* map, int* width, int* height);
+    status_t initTexture(Texture* texture, AssetManager& asset, const char* name,
+        bool premultiplyAlpha = true);
+    status_t initTexture(FileMap* map, int* width, int* height,
+        bool premultiplyAlpha = true);
     status_t initFont(Font* font, const char* fallback);
+    void initShaders();
     bool android();
     bool movie();
     void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
@@ -173,6 +184,7 @@
     void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
     void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
                    const Animation::Part& part, int fadedFramesCount);
+    void drawTexturedQuad(float xStart, float yStart, float width, float height);
     bool validClock(const Animation::Part& part);
     Animation* loadAnimation(const String8&);
     bool playAnimation(const Animation&);
@@ -192,6 +204,7 @@
     void checkExit();
 
     void handleViewport(nsecs_t timestep);
+    void initDynamicColors();
 
     sp<SurfaceComposerClient>       mSession;
     AssetManager mAssets;
@@ -218,6 +231,13 @@
     sp<TimeCheckThread> mTimeCheckThread = nullptr;
     sp<Callbacks> mCallbacks;
     Animation* mAnimation = nullptr;
+    GLuint mImageShader;
+    GLuint mTextShader;
+    GLuint mImageFadeLocation;
+    GLuint mImageTextureLocation;
+    GLuint mTextCropAreaLocation;
+    GLuint mTextTextureLocation;
+    GLuint mImageColorProgressLocation;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/cmds/bootanimation/OWNERS b/cmds/bootanimation/OWNERS
new file mode 100644
index 0000000..b6fb007
--- /dev/null
+++ b/cmds/bootanimation/OWNERS
@@ -0,0 +1,3 @@
+dupin@google.com
+shanh@google.com
+jreck@google.com
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4b054f4..e39636d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5387,8 +5387,8 @@
             contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
             // Use different highlighted colors for conversations' unread count
             if (p.mHighlightExpander) {
-                pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor);
-                textColor = Colors.flattenAlpha(bgColor, pillColor);
+                pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
+                textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor);
             }
             contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
             contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@@ -6247,8 +6247,9 @@
          *
          * @param color the color to check
          * @return true if the color has higher contrast with white than black
+         * @hide
          */
-        private static boolean isColorDark(int color) {
+        public static boolean isColorDark(int color) {
             // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
             return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
         }
@@ -12305,6 +12306,8 @@
         private int mSecondaryTextColor = COLOR_INVALID;
         private int mPrimaryAccentColor = COLOR_INVALID;
         private int mSecondaryAccentColor = COLOR_INVALID;
+        private int mTertiaryAccentColor = COLOR_INVALID;
+        private int mOnAccentTextColor = COLOR_INVALID;
         private int mErrorColor = COLOR_INVALID;
         private int mContrastColor = COLOR_INVALID;
         private int mRippleAlpha = 0x33;
@@ -12362,7 +12365,7 @@
 
             if (isColorized) {
                 if (rawColor == COLOR_DEFAULT) {
-                    int[] attrs = {R.attr.colorAccentTertiary};
+                    int[] attrs = {R.attr.colorAccentSecondary};
                     try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
                         mBackgroundColor = getColor(ta, 0, Color.WHITE);
                     }
@@ -12379,6 +12382,8 @@
                 mContrastColor = mPrimaryTextColor;
                 mPrimaryAccentColor = mPrimaryTextColor;
                 mSecondaryAccentColor = mSecondaryTextColor;
+                mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
+                mOnAccentTextColor = mBackgroundColor;
                 mErrorColor = mPrimaryTextColor;
                 mRippleAlpha = 0x33;
             } else {
@@ -12389,6 +12394,8 @@
                         R.attr.textColorSecondary,
                         R.attr.colorAccent,
                         R.attr.colorAccentSecondary,
+                        R.attr.colorAccentTertiary,
+                        R.attr.textColorOnAccent,
                         R.attr.colorError,
                         R.attr.colorControlHighlight
                 };
@@ -12399,8 +12406,10 @@
                     mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
                     mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
                     mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
-                    mErrorColor = getColor(ta, 6, COLOR_INVALID);
-                    mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
+                    mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
+                    mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
+                    mErrorColor = getColor(ta, 8, COLOR_INVALID);
+                    mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
                 }
                 mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
                         mBackgroundColor, nightMode);
@@ -12420,6 +12429,14 @@
                 if (mSecondaryAccentColor == COLOR_INVALID) {
                     mSecondaryAccentColor = mContrastColor;
                 }
+                if (mTertiaryAccentColor == COLOR_INVALID) {
+                    mTertiaryAccentColor = mContrastColor;
+                }
+                if (mOnAccentTextColor == COLOR_INVALID) {
+                    mOnAccentTextColor = ColorUtils.setAlphaComponent(
+                            ContrastColorUtil.resolvePrimaryColor(
+                                    ctx, mTertiaryAccentColor, nightMode), 0xFF);
+                }
                 if (mErrorColor == COLOR_INVALID) {
                     mErrorColor = mPrimaryTextColor;
                 }
@@ -12485,6 +12502,16 @@
             return mSecondaryAccentColor;
         }
 
+        /** @return the theme's tertiary accent color for colored UI elements. */
+        public @ColorInt int getTertiaryAccentColor() {
+            return mTertiaryAccentColor;
+        }
+
+        /** @return the theme's text color to be used on the tertiary accent color. */
+        public @ColorInt int getOnAccentTextColor() {
+            return mOnAccentTextColor;
+        }
+
         /**
          * @return the contrast-adjusted version of the color provided by the app, or the
          * primary text color when colorized.
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index dae565e..67f631f 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -281,6 +281,32 @@
     }
 
     /**
+     * Convenience method for callers who need to indicate that some other package or
+     * some other user needs a backup pass. This can be useful in the case of groups of
+     * packages that share a uid and/or have user-specific data.
+     * <p>
+     * This method requires that the application hold the "android.permission.BACKUP"
+     * permission if the package named in the package argument does not run under the
+     * same uid as the caller. This method also requires that the application hold the
+     * "android.permission.INTERACT_ACROSS_USERS_FULL" if the user argument is not the
+     * same as the user the caller is running under.
+     * @param userId The user to back up
+     * @param packageName The package name identifying the application to back up.
+     *
+     * @hide
+     */
+    public static void dataChangedForUser(int userId, String packageName) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.dataChangedForUser(userId, packageName);
+            } catch (RemoteException e) {
+                Log.e(TAG, "dataChanged(userId,pkg) couldn't connect");
+            }
+        }
+    }
+
+    /**
      * @deprecated Applications shouldn't request a restore operation using this method. In Android
      * P and later, this method is a no-op.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ac520e8..70eab22 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14915,6 +14915,16 @@
                 "power_button_long_press";
 
         /**
+         * Override internal R.integer.config_longPressOnPowerDurationMs. It determines the length
+         * of power button press to be considered a long press in milliseconds.
+         * Used by PhoneWindowManager.
+         * @hide
+         */
+        @Readable
+        public static final String POWER_BUTTON_LONG_PRESS_DURATION_MS =
+                "power_button_long_press_duration_ms";
+
+        /**
          * Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
          * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
          * Used by PhoneWindowManager.
diff --git a/core/java/android/view/ScrollCaptureResponse.java b/core/java/android/view/ScrollCaptureResponse.java
index 8808827..758f9ab 100644
--- a/core/java/android/view/ScrollCaptureResponse.java
+++ b/core/java/android/view/ScrollCaptureResponse.java
@@ -53,6 +53,10 @@
     @Nullable
     private String mWindowTitle = null;
 
+    /** The package which owns the window. */
+    @Nullable
+    private String mPackageName = null;
+
     /** Carries additional logging and debugging information when enabled. */
     @NonNull
     @DataClass.PluralOf("message")
@@ -77,7 +81,7 @@
 
 
 
-    // Code below generated by codegen v1.0.22.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -97,6 +101,7 @@
             @Nullable Rect windowBounds,
             @Nullable Rect boundsInWindow,
             @Nullable String windowTitle,
+            @Nullable String packageName,
             @NonNull ArrayList<String> messages) {
         this.mDescription = description;
         com.android.internal.util.AnnotationValidations.validate(
@@ -105,6 +110,7 @@
         this.mWindowBounds = windowBounds;
         this.mBoundsInWindow = boundsInWindow;
         this.mWindowTitle = windowTitle;
+        this.mPackageName = packageName;
         this.mMessages = messages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessages);
@@ -153,6 +159,14 @@
     }
 
     /**
+     * The package name of the process the window is owned by.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
      * Carries additional logging and debugging information when enabled.
      */
     @DataClass.Generated.Member
@@ -172,6 +186,7 @@
                 "windowBounds = " + mWindowBounds + ", " +
                 "boundsInWindow = " + mBoundsInWindow + ", " +
                 "windowTitle = " + mWindowTitle + ", " +
+                "packageName = " + mPackageName + ", " +
                 "messages = " + mMessages +
         " }";
     }
@@ -187,12 +202,14 @@
         if (mWindowBounds != null) flg |= 0x4;
         if (mBoundsInWindow != null) flg |= 0x8;
         if (mWindowTitle != null) flg |= 0x10;
+        if (mPackageName != null) flg |= 0x20;
         dest.writeByte(flg);
         dest.writeString(mDescription);
         if (mConnection != null) dest.writeStrongInterface(mConnection);
         if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
         if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
         if (mWindowTitle != null) dest.writeString(mWindowTitle);
+        if (mPackageName != null) dest.writeString(mPackageName);
         dest.writeStringList(mMessages);
     }
 
@@ -213,6 +230,7 @@
         Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
         Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
         String windowTitle = (flg & 0x10) == 0 ? null : in.readString();
+        String packageName = (flg & 0x20) == 0 ? null : in.readString();
         ArrayList<String> messages = new ArrayList<>();
         in.readStringList(messages);
 
@@ -223,6 +241,7 @@
         this.mWindowBounds = windowBounds;
         this.mBoundsInWindow = boundsInWindow;
         this.mWindowTitle = windowTitle;
+        this.mPackageName = packageName;
         this.mMessages = messages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessages);
@@ -256,6 +275,7 @@
         private @Nullable Rect mWindowBounds;
         private @Nullable Rect mBoundsInWindow;
         private @Nullable String mWindowTitle;
+        private @Nullable String mPackageName;
         private @NonNull ArrayList<String> mMessages;
 
         private long mBuilderFieldsSet = 0L;
@@ -319,12 +339,23 @@
         }
 
         /**
+         * The package name of the process the window is owned by.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setPackageName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mPackageName = value;
+            return this;
+        }
+
+        /**
          * Carries additional logging and debugging information when enabled.
          */
         @DataClass.Generated.Member
         public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x20;
+            mBuilderFieldsSet |= 0x40;
             mMessages = value;
             return this;
         }
@@ -340,7 +371,7 @@
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull ScrollCaptureResponse build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x40; // Mark builder used
+            mBuilderFieldsSet |= 0x80; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mDescription = "";
@@ -358,6 +389,9 @@
                 mWindowTitle = null;
             }
             if ((mBuilderFieldsSet & 0x20) == 0) {
+                mPackageName = null;
+            }
+            if ((mBuilderFieldsSet & 0x40) == 0) {
                 mMessages = new ArrayList<>();
             }
             ScrollCaptureResponse o = new ScrollCaptureResponse(
@@ -366,12 +400,13 @@
                     mWindowBounds,
                     mBoundsInWindow,
                     mWindowTitle,
+                    mPackageName,
                     mMessages);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x40) != 0) {
+            if ((mBuilderFieldsSet & 0x80) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -379,10 +414,10 @@
     }
 
     @DataClass.Generated(
-            time = 1614833185795L,
-            codegenVersion = "1.0.22",
+            time = 1628630366187L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java",
-            inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic  boolean isConnected()\npublic  void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic  boolean isConnected()\npublic  void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3550a31..985f20b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -9493,6 +9493,7 @@
 
         ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
         response.setWindowTitle(getTitle().toString());
+        response.setPackageName(mContext.getPackageName());
 
         StringWriter writer =  new StringWriter();
         IndentingPrintWriter pw = new IndentingPrintWriter(writer);
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 8b3c133..7a712e5 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -291,10 +291,10 @@
      * Finds a suitable color such that there's enough contrast.
      *
      * @param color the color to start searching from.
-     * @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
-     * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
+     * @param other the color to ensure contrast against. Assumed to be lighter than {@code color}
+     * @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
      * @param minRatio the minimum contrast ratio required.
-     * @return a color with the same hue as {@param color}, potentially darkened to meet the
+     * @return a color with the same hue as {@code color}, potentially darkened to meet the
      *          contrast ratio.
      */
     public static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
@@ -331,7 +331,7 @@
      * @param color the color to start searching from.
      * @param backgroundColor the color to ensure contrast against.
      * @param minRatio the minimum contrast ratio required.
-     * @return the same color as {@param color} with potentially modified alpha to meet contrast
+     * @return the same color as {@code color} with potentially modified alpha to meet contrast
      */
     public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
         int fg = color;
@@ -361,10 +361,10 @@
      * Finds a suitable color such that there's enough contrast.
      *
      * @param color the color to start searching from.
-     * @param other the color to ensure contrast against. Assumed to be darker than {@param color}
-     * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
+     * @param other the color to ensure contrast against. Assumed to be darker than {@code color}
+     * @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
      * @param minRatio the minimum contrast ratio required.
-     * @return a color with the same hue as {@param color}, potentially darkened to meet the
+     * @return a color with the same hue as {@code color}, potentially lightened to meet the
      *          contrast ratio.
      */
     public static int findContrastColorAgainstDark(int color, int other, boolean findFg,
@@ -393,7 +393,8 @@
                 low = l;
             }
         }
-        return findFg ? fg : bg;
+        hsl[2] = high;
+        return ColorUtilsFromCompat.HSLToColor(hsl);
     }
 
     public static int ensureTextContrastOnBlack(int color) {
@@ -452,7 +453,7 @@
     }
 
     /**
-     * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
+     * Resolves {@code color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
      */
     public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
         if (color == Notification.COLOR_DEFAULT) {
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 0c2d2a9..3191e23 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -53,6 +53,8 @@
     private int mEmphasizedHeight;
     private int mRegularHeight;
     @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
+    int mNumNotGoneChildren;
+    int mNumPriorityChildren;
 
     public NotificationActionListLayout(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -76,15 +78,14 @@
                 && ((EmphasizedNotificationButton) actionView).isPriority();
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int N = getChildCount();
+    private void countAndRebuildMeasureOrder() {
+        final int numChildren = getChildCount();
         int textViews = 0;
         int otherViews = 0;
-        int notGoneChildren = 0;
-        int priorityChildren = 0;
+        mNumNotGoneChildren = 0;
+        mNumPriorityChildren = 0;
 
-        for (int i = 0; i < N; i++) {
+        for (int i = 0; i < numChildren; i++) {
             View c = getChildAt(i);
             if (c instanceof TextView) {
                 textViews++;
@@ -92,9 +93,9 @@
                 otherViews++;
             }
             if (c.getVisibility() != GONE) {
-                notGoneChildren++;
+                mNumNotGoneChildren++;
                 if (isPriority(c)) {
-                    priorityChildren++;
+                    mNumPriorityChildren++;
                 }
             }
         }
@@ -119,17 +120,20 @@
         if (needRebuild) {
             rebuildMeasureOrder(textViews, otherViews);
         }
+    }
 
+    private int measureAndGetUsedWidth(int widthMeasureSpec, int heightMeasureSpec, int innerWidth,
+            boolean collapsePriorityActions) {
+        final int numChildren = getChildCount();
         final boolean constrained =
                 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
-
-        final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
         final int otherSize = mMeasureOrderOther.size();
         int usedWidth = 0;
 
+        int maxPriorityWidth = 0;
         int measuredChildren = 0;
         int measuredPriorityChildren = 0;
-        for (int i = 0; i < N; i++) {
+        for (int i = 0; i < numChildren; i++) {
             // Measure shortest children first. To avoid measuring twice, we approximate by looking
             // at the text length.
             final boolean isPriority;
@@ -154,12 +158,20 @@
                 // measure in the order of (approx.) size, a large view can still take more than its
                 // share if the others are small.
                 int availableWidth = innerWidth - usedWidth;
-                int unmeasuredChildren = notGoneChildren - measuredChildren;
+                int unmeasuredChildren = mNumNotGoneChildren - measuredChildren;
                 int maxWidthForChild = availableWidth / unmeasuredChildren;
-                if (isPriority) {
+                if (isPriority && collapsePriorityActions) {
+                    // Collapsing the actions to just the width required to show the icon.
+                    if (maxPriorityWidth == 0) {
+                        maxPriorityWidth = getResources().getDimensionPixelSize(
+                                R.dimen.notification_actions_collapsed_priority_width);
+                    }
+                    maxWidthForChild = maxPriorityWidth + lp.leftMargin + lp.rightMargin;
+                } else if (isPriority) {
                     // Priority children get a larger maximum share of the total space:
                     //  maximum priority share = (nPriority + 1) / (MAX + 1)
-                    int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren;
+                    int unmeasuredPriorityChildren = mNumPriorityChildren
+                            - measuredPriorityChildren;
                     int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
                     int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
                             / (Notification.MAX_ACTION_BUTTONS + 1);
@@ -187,6 +199,19 @@
         } else {
             mExtraStartPadding = 0;
         }
+        return usedWidth;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        countAndRebuildMeasureOrder();
+        final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
+        int usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth,
+                false /* collapsePriorityButtons */);
+        if (mNumPriorityChildren != 0 && usedWidth >= innerWidth) {
+            usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth,
+                    true /* collapsePriorityButtons */);
+        }
 
         mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding;
         setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c3d1596..6bc00e2 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -771,6 +771,8 @@
     optional SettingProto power_manager_constants = 93;
     reserved 94; // Used to be priv_app_oob_enabled
 
+    optional SettingProto power_button_long_press_duration_ms = 154 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     message PrepaidSetup {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -1063,5 +1065,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 154;
+    // Next tag = 155;
 }
diff --git a/core/res/res/drawable/btn_notification_emphasized.xml b/core/res/res/drawable/btn_notification_emphasized.xml
index 29c51f2a..7c09fb8 100644
--- a/core/res/res/drawable/btn_notification_emphasized.xml
+++ b/core/res/res/drawable/btn_notification_emphasized.xml
@@ -24,9 +24,9 @@
             android:insetBottom="@dimen/button_inset_vertical_material">
             <shape android:shape="rectangle">
                 <corners android:radius="@dimen/notification_action_button_radius" />
-                <padding android:left="12dp"
+                <padding android:left="16dp"
                          android:top="@dimen/button_padding_vertical_material"
-                         android:right="12dp"
+                         android:right="16dp"
                          android:bottom="@dimen/button_padding_vertical_material" />
                 <solid android:color="@color/white" />
             </shape>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index db43b5b..e1e1201 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -957,6 +957,20 @@
     -->
     <integer name="config_longPressOnPowerBehavior">5</integer>
 
+    <!-- The time in milliseconds after which a press on power button is considered "long". -->
+    <integer name="config_longPressOnPowerDurationMs">500</integer>
+
+    <!-- The possible UI options to be surfaced for configuring long press power on duration
+         action. Value set in config_longPressOnPowerDurationMs should be one of the available
+         options to allow users to restore default. -->
+    <integer-array name="config_longPressOnPowerDurationSettings">
+        <item>250</item>
+        <item>350</item>
+        <item>500</item>
+        <item>650</item>
+        <item>750</item>
+    </integer-array>
+
     <!-- Whether the setting to change long press on power behaviour from default to assistant (5)
          is available in Settings.
      -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index de7a117..2baed43 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -237,6 +237,9 @@
          value is calculated in ConversationLayout#updateActionListPadding() -->
     <dimen name="notification_actions_padding_start">36dp</dimen>
 
+    <!-- The max width of a priority action button when it is collapsed to just the icon. -->
+    <dimen name="notification_actions_collapsed_priority_width">60dp</dimen>
+
     <!-- The start padding to optionally use (e.g. if there's extra space) for CallStyle
          notification actions.
          this = conversation_content_start (80dp) - button inset (4dp) - action padding (12dp) -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index adb046e..6802ae5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -439,6 +439,8 @@
   <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_immersive_mode_confirmation_panic" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
+  <java-symbol type="integer" name="config_longPressOnPowerDurationMs" />
+  <java-symbol type="array" name="config_longPressOnPowerDurationSettings" />
   <java-symbol type="bool" name="config_longPressOnPowerForAssistantSettingAvailable" />
   <java-symbol type="integer" name="config_veryLongPressOnPowerBehavior" />
   <java-symbol type="integer" name="config_veryLongPressTimeout" />
@@ -3183,6 +3185,7 @@
 
   <java-symbol type="id" name="notification_action_list_margin_target" />
   <java-symbol type="dimen" name="notification_actions_padding_start"/>
+  <java-symbol type="dimen" name="notification_actions_collapsed_priority_width"/>
   <java-symbol type="dimen" name="notification_action_disabled_alpha" />
   <java-symbol type="id" name="tag_margin_end_when_icon_visible" />
   <java-symbol type="id" name="tag_margin_end_when_icon_gone" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index cd07d46..685671b 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -399,6 +399,8 @@
             assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor());
             assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor());
             assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor());
+            assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor());
+            assertEquals(cDay.getOnAccentTextColor(), cNight.getOnAccentTextColor());
             assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
             assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
             assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
@@ -413,20 +415,26 @@
         assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getOnAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getRippleAlpha()).isAtLeast(0x00);
         assertThat(c.getRippleAlpha()).isAtMost(0xff);
 
-        // Assert that various colors have sufficient contrast
+        // Assert that various colors have sufficient contrast with the background
         assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5);
 
-        // This accent color is only used for emphasized buttons
+        // These colors are only used for emphasized buttons; they do not need contrast
         assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
+        assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1);
+
+        // The text that is used within the accent color DOES need to have contrast
+        assertContrastIsAtLeast(c.getOnAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
     }
 
     private void assertContrastIsAtLeast(int foreground, int background, double minContrast) {
diff --git a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
new file mode 100644
index 0000000..9da720c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.internal.util;
+
+import static androidx.core.graphics.ColorUtils.calculateContrast;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Color;
+
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+public class ContrastColorUtilTest extends TestCase {
+
+    @SmallTest
+    public void testEnsureTextContrastAgainstDark() {
+        int darkBg = 0xFF35302A;
+
+        int blueContrastColor = ContrastColorUtil.ensureTextContrast(Color.BLUE, darkBg, true);
+        assertContrastIsWithinRange(blueContrastColor, darkBg, 4.5, 4.75);
+
+        int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, darkBg, true);
+        assertContrastIsWithinRange(redContrastColor, darkBg, 4.5, 4.75);
+
+        final int darkGreen = 0xff008800;
+        int greenContrastColor = ContrastColorUtil.ensureTextContrast(darkGreen, darkBg, true);
+        assertContrastIsWithinRange(greenContrastColor, darkBg, 4.5, 4.75);
+
+        int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.DKGRAY, darkBg, true);
+        assertContrastIsWithinRange(grayContrastColor, darkBg, 4.5, 4.75);
+
+        int selfContrastColor = ContrastColorUtil.ensureTextContrast(darkBg, darkBg, true);
+        assertContrastIsWithinRange(selfContrastColor, darkBg, 4.5, 4.75);
+    }
+
+    @SmallTest
+    public void testEnsureTextContrastAgainstLight() {
+        int lightBg = 0xFFFFF8F2;
+
+        final int lightBlue = 0xff8888ff;
+        int blueContrastColor = ContrastColorUtil.ensureTextContrast(lightBlue, lightBg, false);
+        assertContrastIsWithinRange(blueContrastColor, lightBg, 4.5, 4.75);
+
+        int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, lightBg, false);
+        assertContrastIsWithinRange(redContrastColor, lightBg, 4.5, 4.75);
+
+        int greenContrastColor = ContrastColorUtil.ensureTextContrast(Color.GREEN, lightBg, false);
+        assertContrastIsWithinRange(greenContrastColor, lightBg, 4.5, 4.75);
+
+        int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.LTGRAY, lightBg, false);
+        assertContrastIsWithinRange(grayContrastColor, lightBg, 4.5, 4.75);
+
+        int selfContrastColor = ContrastColorUtil.ensureTextContrast(lightBg, lightBg, false);
+        assertContrastIsWithinRange(selfContrastColor, lightBg, 4.5, 4.75);
+    }
+
+    private void assertContrastIsWithinRange(int foreground, int background,
+            double minContrast, double maxContrast) {
+        assertContrastIsAtLeast(foreground, background, minContrast);
+        assertContrastIsAtMost(foreground, background, maxContrast);
+    }
+
+    private void assertContrastIsAtLeast(int foreground, int background, double minContrast) {
+        try {
+            assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast);
+        } catch (AssertionError e) {
+            throw new AssertionError(
+                    String.format("Insufficient contrast: foreground=#%08x background=#%08x",
+                            foreground, background), e);
+        }
+    }
+
+    private void assertContrastIsAtMost(int foreground, int background, double maxContrast) {
+        try {
+            assertThat(calculateContrast(foreground, background)).isAtMost(maxContrast);
+        } catch (AssertionError e) {
+            throw new AssertionError(
+                    String.format("Excessive contrast: foreground=#%08x background=#%08x",
+                            foreground, background), e);
+        }
+    }
+
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index f3cfcf1..67358c4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -579,7 +579,7 @@
         //
         // Note: mNamespace == KeyProperties.NAMESPACE_APPLICATION implies that the target domain
         // is Domain.APP and Domain.SELINUX is the target domain otherwise.
-        if (alias != descriptor.alias
+        if (!alias.equals(descriptor.alias)
                 || descriptor.domain != targetDomain
                 || (descriptor.domain == Domain.SELINUX && descriptor.nspace != targetNamespace)) {
             throw new KeyStoreException("Can only replace keys with same alias: " + alias
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index c0df06f..ac97c8f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -576,20 +576,17 @@
                 mBubbleContainer.setActiveController(mStackAnimationController);
                 hideFlyoutImmediate();
 
-                if (!mPositioner.showingInTaskbar()) {
-                    // Also, save the magnetized stack so we can dispatch touch events to it.
-                    mMagnetizedObject = mStackAnimationController.getMagnetizedStack(
-                            mMagneticTarget);
-                    mMagnetizedObject.setMagnetListener(mStackMagnetListener);
-                } else {
+                if (mPositioner.showingInTaskbar()) {
                     // In taskbar, the stack isn't draggable so we shouldn't dispatch touch events.
                     mMagnetizedObject = null;
+                } else {
+                    // Save the magnetized stack so we can dispatch touch events to it.
+                    mMagnetizedObject = mStackAnimationController.getMagnetizedStack();
+                    mMagnetizedObject.clearAllTargets();
+                    mMagnetizedObject.addTarget(mMagneticTarget);
+                    mMagnetizedObject.setMagnetListener(mStackMagnetListener);
                 }
 
-                // Also, save the magnetized stack so we can dispatch touch events to it.
-                mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget);
-                mMagnetizedObject.setMagnetListener(mStackMagnetListener);
-
                 mIsDraggingStack = true;
 
                 // Cancel animations to make the stack temporarily invisible, since we're now
@@ -881,7 +878,6 @@
                         mRelativeStackPositionBeforeRotation = null;
                     }
 
-                    setUpDismissView();
                     if (mIsExpanded) {
                         // Re-draw bubble row and pointer for new orientation.
                         beforeExpandedViewAnimation();
@@ -1043,10 +1039,9 @@
                 contentResolver, "bubble_dismiss_radius", mBubbleSize * 2 /* default */);
 
         // Save the MagneticTarget instance for the newly set up view - we'll add this to the
-        // MagnetizedObjects.
+        // MagnetizedObjects when the dismiss view gets shown.
         mMagneticTarget = new MagnetizedObject.MagneticTarget(
                 mDismissView.getCircle(), dismissRadius);
-
         mBubbleContainer.bringToFront();
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 0802fb5..636e145 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -1024,11 +1024,9 @@
     }
 
     /**
-     * Returns the {@link MagnetizedObject} instance for the bubble stack, with the provided
-     * {@link MagnetizedObject.MagneticTarget} added as a target.
+     * Returns the {@link MagnetizedObject} instance for the bubble stack.
      */
-    public MagnetizedObject<StackAnimationController> getMagnetizedStack(
-            MagnetizedObject.MagneticTarget target) {
+    public MagnetizedObject<StackAnimationController> getMagnetizedStack() {
         if (mMagnetizedStack == null) {
             mMagnetizedStack = new MagnetizedObject<StackAnimationController>(
                     mLayout.getContext(),
@@ -1053,7 +1051,6 @@
                     loc[1] = (int) mStackPosition.y;
                 }
             };
-            mMagnetizedStack.addTarget(target);
             mMagnetizedStack.setHapticsEnabled(true);
             mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
index 9f6dd1f..9e01259 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
@@ -303,6 +303,13 @@
     }
 
     /**
+     * Removes all associated targets from this object.
+     */
+    fun clearAllTargets() {
+        associatedTargets.clear()
+    }
+
+    /**
      * Provide this method with all motion events that move the magnetized object. If the
      * location of the motion events moves within the magnetic field of a target, or indicate a
      * fling-to-target gesture, this method will return true and you should not move the object
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index a5e96d1..20021eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -28,6 +28,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -45,7 +46,7 @@
 class SizeCompatUILayout {
     private static final String TAG = "SizeCompatUILayout";
 
-    private final SyncTransactionQueue mSyncQueue;
+    final SyncTransactionQueue mSyncQueue;
     private final SizeCompatUIController.SizeCompatUICallback mCallback;
     private Context mContext;
     private Configuration mTaskConfig;
@@ -306,6 +307,10 @@
 
     private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) {
         mSyncQueue.runInSync(t -> {
+            if (!leash.isValid()) {
+                Log.w(TAG, "The leash has been released.");
+                return;
+            }
             t.setPosition(leash, positionX, positionY);
             // The size compat UI should be the topmost child of the Task in case there can be more
             // than one children.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
index f634c45..82f69c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
@@ -110,7 +110,8 @@
         }
 
         if (mLeash != null) {
-            new SurfaceControl.Transaction().remove(mLeash).apply();
+            final SurfaceControl leash = mLeash;
+            mLayout.mSyncQueue.runInSync(t -> t.remove(leash));
             mLeash = null;
         }
     }
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 48cdf16..197b7b2 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -31,7 +31,7 @@
             android:directBootAware="true">
 
         <receiver android:name=".TemporaryFileManager"
-            android:exported="true">
+            android:exported="false">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
@@ -76,7 +76,7 @@
 
         <receiver android:name=".InstallEventReceiver"
                 android:permission="android.permission.INSTALL_PACKAGES"
-                android:exported="true">
+                android:exported="false">
             <intent-filter android:priority="1">
                 <action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
             </intent-filter>
@@ -106,14 +106,14 @@
 
         <receiver android:name=".UninstallEventReceiver"
             android:permission="android.permission.INSTALL_PACKAGES"
-            android:exported="true">
+            android:exported="false">
             <intent-filter android:priority="1">
                 <action android:name="com.android.packageinstaller.ACTION_UNINSTALL_COMMIT" />
             </intent-filter>
         </receiver>
 
         <receiver android:name=".PackageInstalledReceiver"
-                android:exported="true">
+                android:exported="false">
             <intent-filter android:priority="1">
                 <action android:name="android.intent.action.PACKAGE_ADDED" />
                 <data android:scheme="package" />
diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING
index 5d7b9bb..cef9014 100644
--- a/packages/PackageInstaller/TEST_MAPPING
+++ b/packages/PackageInstaller/TEST_MAPPING
@@ -19,6 +19,9 @@
     },
     {
       "name": "CtsPackageUninstallTestCases"
+    },
+    {
+      "name": "PackageInstallerTests"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 72fa25f..bf0dc7b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -157,7 +157,6 @@
     private Network mDefaultNetwork = null;
     private NetworkCapabilities mDefaultNetworkCapabilities = null;
     private final Runnable mCallback;
-    private final boolean mSupportMergedUi;
 
     private WifiInfo mWifiInfo;
     public boolean enabled;
@@ -181,7 +180,6 @@
         mNetworkScoreManager = networkScoreManager;
         mConnectivityManager = connectivityManager;
         mCallback = callback;
-        mSupportMergedUi = false;
     }
 
     public void setListening(boolean listening) {
@@ -223,10 +221,8 @@
                 } else {
                     ssid = getValidSsid(mWifiInfo);
                 }
-                if (mSupportMergedUi) {
-                    isCarrierMerged = mWifiInfo.isCarrierMerged();
-                    subId = mWifiInfo.getSubscriptionId();
-                }
+                isCarrierMerged = mWifiInfo.isCarrierMerged();
+                subId = mWifiInfo.getSubscriptionId();
                 updateRssi(mWifiInfo.getRssi());
                 maybeRequestNetworkScore();
             }
@@ -255,10 +251,8 @@
             } else {
                 ssid = getValidSsid(mWifiInfo);
             }
-            if (mSupportMergedUi) {
-                isCarrierMerged = mWifiInfo.isCarrierMerged();
-                subId = mWifiInfo.getSubscriptionId();
-            }
+            isCarrierMerged = mWifiInfo.isCarrierMerged();
+            subId = mWifiInfo.getSubscriptionId();
             updateRssi(mWifiInfo.getRssi());
             maybeRequestNetworkScore();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 6100615..56454e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -20,10 +20,13 @@
 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason;
 
 import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
 import android.net.wifi.WifiInfo;
+import android.os.Bundle;
 import android.os.SystemClock;
 
 import androidx.annotation.VisibleForTesting;
@@ -36,6 +39,23 @@
 
     private static final int INVALID_RSSI = -127;
 
+    /**
+     * The intent action shows network details settings to allow configuration of Wi-Fi.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: The calling package should put the chosen
+     * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
+     * the {@link #KEY_CHOSEN_WIFIENTRY_KEY}.
+     * <p>
+     * Output: Nothing.
+     */
+    public static final String ACTION_WIFI_DETAILS_SETTINGS =
+            "android.settings.WIFI_DETAILS_SETTINGS";
+    public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key";
+    public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
+
     static final int[] WIFI_PIE = {
             com.android.internal.R.drawable.ic_wifi_signal_0,
             com.android.internal.R.drawable.ic_wifi_signal_1,
@@ -275,7 +295,42 @@
         return noInternet ? NO_INTERNET_WIFI_PIE[level] : WIFI_PIE[level];
     }
 
+    /**
+     * Wrapper the {@link #getInternetIconResource} for testing compatibility.
+     */
+    public static class InternetIconInjector {
+
+        protected final Context mContext;
+
+        public InternetIconInjector(Context context) {
+            mContext = context;
+        }
+
+        /**
+         * Returns the Internet icon for a given RSSI level.
+         *
+         * @param noInternet True if a connected Wi-Fi network cannot access the Internet
+         * @param level The number of bars to show (0-4)
+         */
+        public Drawable getIcon(boolean noInternet, int level) {
+            return mContext.getDrawable(WifiUtils.getInternetIconResource(level, noInternet));
+        }
+    }
+
     public static boolean isMeteredOverridden(WifiConfiguration config) {
         return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE;
     }
+
+    /**
+     * Returns the Intent for Wi-Fi network details settings.
+     *
+     * @param key The Wi-Fi entry key
+     */
+    public static Intent getWifiDetailsSettingsIntent(String key) {
+        final Intent intent = new Intent(ACTION_WIFI_DETAILS_SETTINGS);
+        final Bundle bundle = new Bundle();
+        bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key);
+        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle);
+        return intent;
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index 89960cb..7c2b904 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -20,9 +20,12 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.Intent;
 import android.net.NetworkKey;
 import android.net.RssiCurve;
 import android.net.ScoredNetwork;
@@ -36,6 +39,8 @@
 import android.text.format.DateUtils;
 import android.util.ArraySet;
 
+import androidx.test.core.app.ApplicationProvider;
+
 import com.android.settingslib.R;
 
 import org.junit.Before;
@@ -44,7 +49,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
 import java.util.Set;
@@ -69,7 +73,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(ApplicationProvider.getApplicationContext());
     }
 
     @Test
@@ -148,6 +152,32 @@
         assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue();
     }
 
+    @Test
+    public void getWifiDetailsSettingsIntent_returnsCorrectValues() {
+        final String key = "test_key";
+
+        final Intent intent = WifiUtils.getWifiDetailsSettingsIntent(key);
+
+        assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DETAILS_SETTINGS);
+        final Bundle bundle = intent.getBundleExtra(WifiUtils.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        assertThat(bundle.getString(WifiUtils.KEY_CHOSEN_WIFIENTRY_KEY)).isEqualTo(key);
+    }
+
+    @Test
+    public void testInternetIconInjector_getIcon_returnsCorrectValues() {
+        WifiUtils.InternetIconInjector iconInjector = new WifiUtils.InternetIconInjector(mContext);
+
+        for (int level = 0; level <= 4; level++) {
+            iconInjector.getIcon(false /* noInternet */, level);
+            verify(mContext).getDrawable(
+                    WifiUtils.getInternetIconResource(level, false /* noInternet */));
+
+            iconInjector.getIcon(true /* noInternet */, level);
+            verify(mContext).getDrawable(
+                    WifiUtils.getInternetIconResource(level, true /* noInternet */));
+        }
+    }
+
     private static ArrayList<ScanResult> buildScanResultCache() {
         ArrayList<ScanResult> scanResults = new ArrayList<>();
         for (int i = 0; i < 5; i++) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index eb81961..a46d28b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -76,5 +76,6 @@
         Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
         Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
         Settings.Global.POWER_BUTTON_LONG_PRESS,
+        Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 6022608..96f127b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -101,6 +101,7 @@
         Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
         Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
         Settings.Secure.QS_TILES,
+        Settings.Secure.QS_AUTO_ADDED_TILES,
         Settings.Secure.CONTROLS_ENABLED,
         Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
         Settings.Secure.DOZE_ENABLED,
@@ -118,7 +119,6 @@
         Settings.Secure.VR_DISPLAY_MODE,
         Settings.Secure.NOTIFICATION_BADGING,
         Settings.Secure.NOTIFICATION_DISMISS_RTL,
-        Settings.Secure.QS_AUTO_ADDED_TILES,
         Settings.Secure.SCREENSAVER_ENABLED,
         Settings.Secure.SCREENSAVER_COMPONENTS,
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 5220a04..84c5feb 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -20,6 +20,7 @@
 import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.PERCENTAGE_INTEGER_VALIDATOR;
 import static android.view.Display.HdrCapabilities.HDR_TYPES;
@@ -140,6 +141,7 @@
                         /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
         VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, NONE_NEGATIVE_LONG_VALIDATOR);
     }
 }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index c577868..6cfcb51 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -72,8 +72,9 @@
      * {@hide}
      */
     private static final ArraySet<String> sBroadcastOnRestore;
+    private static final ArraySet<String> sBroadcastOnRestoreSystemUI;
     static {
-        sBroadcastOnRestore = new ArraySet<String>(4);
+        sBroadcastOnRestore = new ArraySet<String>(9);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -83,6 +84,9 @@
         sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
         sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
         sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
+        sBroadcastOnRestoreSystemUI = new ArraySet<String>(2);
+        sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES);
+        sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_AUTO_ADDED_TILES);
     }
 
     private interface SettingsLookup {
@@ -133,6 +137,7 @@
         // Will we need a post-restore broadcast for this element?
         String oldValue = null;
         boolean sendBroadcast = false;
+        boolean sendBroadcastSystemUI = false;
         final SettingsLookup table;
 
         if (destination.equals(Settings.Secure.CONTENT_URI)) {
@@ -143,10 +148,12 @@
             table = sGlobalLookup;
         }
 
-        if (sBroadcastOnRestore.contains(name)) {
+        sendBroadcast = sBroadcastOnRestore.contains(name);
+        sendBroadcastSystemUI = sBroadcastOnRestoreSystemUI.contains(name);
+
+        if (sendBroadcast || sendBroadcastSystemUI) {
             // TODO: http://b/22388012
             oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM);
-            sendBroadcast = true;
         }
 
         try {
@@ -193,18 +200,28 @@
         } catch (Exception e) {
             // If we fail to apply the setting, by definition nothing happened
             sendBroadcast = false;
+            sendBroadcastSystemUI = false;
         } finally {
             // If this was an element of interest, send the "we just restored it"
             // broadcast with the historical value now that the new value has
             // been committed and observers kicked off.
-            if (sendBroadcast) {
+            if (sendBroadcast || sendBroadcastSystemUI) {
                 Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
-                        .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+                        .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                         .putExtra(Intent.EXTRA_SETTING_NAME, name)
                         .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value)
                         .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue)
                         .putExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, restoredFromSdkInt);
-                context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
+
+                if (sendBroadcast) {
+                    intent.setPackage("android");
+                    context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
+                }
+                if (sendBroadcastSystemUI) {
+                    intent.setPackage(
+                            context.getString(com.android.internal.R.string.config_systemUi));
+                    context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
+                }
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 073b4d0..90cec3f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1195,6 +1195,9 @@
         dumpSetting(s, p,
                 Settings.Global.POWER_MANAGER_CONSTANTS,
                 GlobalSettingsProto.POWER_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS,
+                GlobalSettingsProto.POWER_BUTTON_LONG_PRESS_DURATION_MS);
 
         final long prepaidSetupToken = p.start(GlobalSettingsProto.PREPAID_SETUP);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/res-keyguard/values/donottranslate.xml b/packages/SystemUI/res-keyguard/values/donottranslate.xml
index a4d0ff7..1934457 100644
--- a/packages/SystemUI/res-keyguard/values/donottranslate.xml
+++ b/packages/SystemUI/res-keyguard/values/donottranslate.xml
@@ -21,6 +21,9 @@
     <!-- Skeleton string format for displaying the date when an alarm is set. -->
     <string name="abbrev_wday_month_day_no_year_alarm">EEEMMMd</string>
 
+    <!-- Skeleton string format for displaying the date shorter. -->
+    <string name="abbrev_month_day_no_year">MMMd</string>
+
     <!-- Skeleton string format for displaying the time in 12-hour format. -->
     <string name="clock_12hr_format">hm</string>
 
diff --git a/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml
new file mode 100644
index 0000000..13133cb
--- /dev/null
+++ b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Copy of progress_indeterminate_horizontal_rect2 in frameworks/base/core/res -->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="2000"
+        android:propertyXName="translateX"
+        android:pathData="M -197.60001,0 c 14.28182,0 85.07782,0 135.54689,0 c 54.26191,0 90.42461,0 168.24331,0 c 144.72154,0 316.40982,0 316.40982,0 "
+        android:interpolator="@interpolator/progress_indeterminate_horizontal_rect2_translatex_copy"
+        android:repeatCount="infinite" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_arrow_forward.xml b/packages/SystemUI/res/drawable/ic_arrow_forward.xml
new file mode 100644
index 0000000..438e4c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_arrow_forward.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:autoMirrored="true"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/black"
+        android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml
new file mode 100644
index 0000000..2c34060
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:tint="?android:attr/colorControlNormal"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2H9V6zM18,20H6V10h12V20zM12,17c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2C10,16.1 10.9,17 12,17z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
new file mode 100644
index 0000000..ac4c43b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
@@ -0,0 +1,29 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml
new file mode 100644
index 0000000..f38a368
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M2,22l16,0l0,-2l-11,0l13,-13l0,1l2,0l0,-6z"
+        android:strokeAlpha="0.3"
+        android:fillAlpha="0.3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,10h2v8h-2z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,20h2v2h-2z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/internet_dialog_background.xml b/packages/SystemUI/res/drawable/internet_dialog_background.xml
new file mode 100644
index 0000000..3ceb0f6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/internet_dialog_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+    <shape android:shape="rectangle">
+        <corners android:radius="8dp" />
+        <solid android:color="?android:attr/colorBackground" />
+    </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml
new file mode 100644
index 0000000..50267fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:shape="rectangle">
+    <stroke
+        android:color="?androidprv:attr/colorAccentPrimaryVariant"
+        android:width="1dp"/>
+    <corners android:radius="20dp"/>
+    <padding
+        android:left="8dp"
+        android:right="8dp"
+        android:top="4dp"
+        android:bottom="4dp" />
+    <solid android:color="@android:color/transparent" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml
new file mode 100644
index 0000000..14672ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+    <shape android:shape="rectangle">
+        <corners
+            android:topLeftRadius="@dimen/internet_dialog_corner_radius"
+            android:topRightRadius="@dimen/internet_dialog_corner_radius"
+            android:bottomLeftRadius="@dimen/internet_dialog_corner_radius"
+            android:bottomRightRadius="@dimen/internet_dialog_corner_radius"/>
+        <solid android:color="?android:attr/colorBackground" />
+    </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 0000000..95209f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Copy of progress_indeterminate_horizontal_material_trimmed in frameworks/base/core/res -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+    <target
+        android:name="rect_grp"
+        android:animation="@anim/progress_indeterminate_horizontal_rect" />
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml
new file mode 100644
index 0000000..088e82b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/settingslib_state_off_color"/>
+            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
+        </shape>
+    </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml
new file mode 100644
index 0000000..250188b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/settingslib_state_on_color"/>
+            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
+        </shape>
+    </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml
new file mode 100644
index 0000000..b41762f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:top="@dimen/settingslib_switch_thumb_margin"
+        android:left="@dimen/settingslib_switch_thumb_margin"
+        android:right="@dimen/settingslib_switch_thumb_margin"
+        android:bottom="@dimen/settingslib_switch_thumb_margin">
+        <shape android:shape="oval">
+            <size
+                android:height="@dimen/settingslib_switch_thumb_size"
+                android:width="@dimen/settingslib_switch_thumb_size"/>
+            <solid
+                android:color="@color/settingslib_thumb_off_color"
+                android:alpha="?android:attr/disabledAlpha"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_off.xml b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml
new file mode 100644
index 0000000..87d4aea
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:top="@dimen/settingslib_switch_thumb_margin"
+        android:bottom="@dimen/settingslib_switch_thumb_margin">
+        <shape android:shape="oval">
+            <size
+                android:height="@dimen/settingslib_switch_thumb_size"
+                android:width="@dimen/settingslib_switch_thumb_size"/>
+            <solid android:color="@color/settingslib_thumb_off_color"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
new file mode 100644
index 0000000..5566ea3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:top="@dimen/settingslib_switch_thumb_margin"
+        android:bottom="@dimen/settingslib_switch_thumb_margin">
+        <shape android:shape="oval">
+            <size
+                android:height="@dimen/settingslib_switch_thumb_size"
+                android:width="@dimen/settingslib_switch_thumb_size"/>
+            <solid android:color="@color/settingslib_state_on_color"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml
new file mode 100644
index 0000000..06bb779
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/settingslib_thumb_on" android:state_checked="true"/>
+    <item android:drawable="@drawable/settingslib_thumb_off" android:state_checked="false"/>
+    <item android:drawable="@drawable/settingslib_thumb_disabled" android:state_enabled="false"/>
+</selector>
diff --git a/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml
new file mode 100644
index 0000000..15dfcb7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle"
+    android:width="@dimen/settingslib_switch_track_width"
+    android:height="@dimen/settingslib_switch_track_height">
+    <solid
+        android:color="@color/settingslib_track_off_color"
+        android:alpha="?android:attr/disabledAlpha"/>
+    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
new file mode 100644
index 0000000..3a09284
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle"
+    android:width="@dimen/settingslib_switch_track_width"
+    android:height="@dimen/settingslib_switch_track_height">
+    <padding android:left="@dimen/settingslib_switch_thumb_margin"
+             android:right="@dimen/settingslib_switch_thumb_margin"/>
+    <solid android:color="@color/settingslib_track_off_color"/>
+    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
new file mode 100644
index 0000000..1d9dacd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle"
+    android:width="@dimen/settingslib_switch_track_width"
+    android:height="@dimen/settingslib_switch_track_height">
+    <padding android:left="@dimen/settingslib_switch_thumb_margin"
+             android:right="@dimen/settingslib_switch_thumb_margin"/>
+    <solid android:color="@color/settingslib_track_on_color"/>
+    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/settingslib_track_selector.xml b/packages/SystemUI/res/drawable/settingslib_track_selector.xml
new file mode 100644
index 0000000..a38c3b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/settingslib_track_selector.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/settingslib_track_on_background" android:state_checked="true"/>
+    <item android:drawable="@drawable/settingslib_track_off_background" android:state_checked="false"/>
+    <item android:drawable="@drawable/settingslib_track_disabled_background" android:state_enabled="false"/>
+</selector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 0000000..aec204f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+     draws the whole height of the progress bar instead having blank space above and below the
+     bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:height="10dp"
+        android:width="340dp"
+        android:viewportHeight="10"
+        android:viewportWidth="340" >
+    <group
+        android:name="progress_group"
+        android:translateX="180"
+        android:translateY="5" >
+        <path
+            android:name="background_track"
+            android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+            android:fillColor="?androidprv:attr/colorSurfaceVariant"/>
+        <group
+            android:name="rect_grp"
+            android:translateX="-197.60001"
+            android:scaleX="0.5" >
+            <path
+                android:name="rect"
+                android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+                android:fillColor="?androidprv:attr/colorAccentPrimaryVariant" />
+        </group>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_toast.xml b/packages/SystemUI/res/layout/global_actions_toast.xml
new file mode 100644
index 0000000..1f08996
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_toast.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center|bottom"
+    android:gravity="center"
+    android:layout_marginBottom="@dimen/global_actions_info_margin"
+    app:layout_constraintBottom_toBottomOf="parent"
+    app:layout_constraintStart_toStartOf="parent"
+    app:layout_constraintEnd_toEndOf="parent"
+    app:layout_constraintWidth_max="382dp"
+    android:layout_weight="0"
+    android:background="@drawable/global_actions_lite_background"
+    android:theme="@style/Theme.SystemUI.QuickSettings"
+    android:paddingTop="14dp"
+    android:paddingBottom="14dp"
+    android:paddingStart="20dp"
+    android:paddingEnd="20dp"
+    android:orientation="horizontal">
+    <TextView
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textSize="14sp"
+        android:textColor="?android:attr/textColorSecondary"
+        android:text="@string/global_action_smart_lock_disabled" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
new file mode 100644
index 0000000..b841419
--- /dev/null
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -0,0 +1,373 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/internet_connectivity_dialog"
+    android:layout_width="@dimen/internet_dialog_list_max_width"
+    android:layout_height="@dimen/internet_dialog_list_max_height"
+    android:background="@drawable/internet_dialog_rounded_top_corner_background"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/Widget.SliceView.Panel"
+        android:gravity="center_vertical|center_horizontal"
+        android:layout_marginTop="24dp"
+        android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/internet_dialog_title"
+            android:gravity="center_vertical|center_horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="32dp"
+            android:textColor="?android:attr/textColorPrimary"
+            android:fontFamily="google-sans"
+            android:textSize="24sp"/>
+
+        <TextView
+            android:id="@+id/internet_dialog_subtitle"
+            android:gravity="center_vertical|center_horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="20dp"
+            android:layout_marginTop="4dp"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:fontFamily="google-sans"
+            android:textSize="14sp"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
+        android:orientation="vertical">
+
+        <View
+            android:id="@+id/divider"
+            android:layout_gravity="center_vertical|center_horizontal"
+            android:layout_width="340dp"
+            android:layout_height="4dp"
+            android:background="?androidprv:attr/colorSurfaceVariant"/>
+
+        <ProgressBar
+            android:id="@+id/wifi_searching_progress"
+            android:indeterminate="true"
+            android:layout_width="340dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:visibility="gone"
+            style="@style/TrimmedHorizontalProgressBar"/>
+    </LinearLayout>
+
+    <androidx.core.widget.NestedScrollView
+        android:id="@+id/scroll_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <LinearLayout
+            android:id="@+id/scroll_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+            <LinearLayout
+                android:id="@+id/internet_list"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:id="@+id/mobile_network_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="88dp"
+                    android:clickable="true"
+                    android:focusable="true"
+                    android:background="?android:attr/selectableItemBackground"
+                    android:layout_gravity="center_vertical|start"
+                    android:orientation="horizontal"
+                    android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                    android:paddingStart="22dp"
+                    android:paddingEnd="22dp">
+
+                    <FrameLayout
+                        android:layout_width="24dp"
+                        android:layout_height="24dp"
+                        android:clickable="false"
+                        android:layout_gravity="center_vertical|start">
+                        <ImageView
+                            android:id="@+id/signal_icon"
+                            android:autoMirrored="true"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"/>
+                    </FrameLayout>
+
+                    <LinearLayout
+                        android:layout_weight="1"
+                        android:id="@+id/mobile_network_list"
+                        android:orientation="vertical"
+                        android:clickable="false"
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent"
+                        android:gravity="start|center_vertical">
+                        <TextView
+                            android:id="@+id/mobile_title"
+                            android:textDirection="locale"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                            android:layout_marginEnd="7dp"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center_vertical|start"
+                            android:ellipsize="end"
+                            android:textColor="?android:attr/textColorPrimary"
+                            android:textSize="16sp"
+                            android:fontFamily="google-sans"/>
+                        <TextView
+                            android:id="@+id/mobile_summary"
+                            android:textDirection="locale"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                            android:layout_marginEnd="34dp"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center_vertical|start"
+                            android:ellipsize="end"
+                            android:textColor="?android:attr/textColorTertiary"
+                            android:textSize="14sp"
+                            android:fontFamily="google-sans"/>
+                    </LinearLayout>
+
+                    <FrameLayout
+                        android:layout_width="@dimen/settingslib_switch_track_width"
+                        android:layout_height="48dp"
+                        android:layout_gravity="end|center_vertical">
+                        <Switch
+                            android:id="@+id/mobile_toggle"
+                            android:switchMinWidth="@dimen/settingslib_switch_track_width"
+                            android:layout_gravity="center"
+                            android:layout_width="@dimen/settingslib_switch_track_width"
+                            android:layout_height="@dimen/settingslib_switch_track_height"
+                            android:track="@drawable/settingslib_track_selector"
+                            android:thumb="@drawable/settingslib_thumb_selector"
+                            android:theme="@style/MainSwitch.Settingslib"/>
+                    </FrameLayout>
+
+                </LinearLayout>
+
+                <LinearLayout
+                    android:id="@+id/turn_on_wifi_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="72dp"
+                    android:clickable="true"
+                    android:focusable="true"
+                    android:background="?android:attr/selectableItemBackground"
+                    android:gravity="center"
+                    android:orientation="horizontal"
+                    android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                    android:paddingStart="22dp"
+                    android:paddingEnd="22dp">
+
+                    <FrameLayout
+                        android:layout_weight="1"
+                        android:orientation="vertical"
+                        android:clickable="false"
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent">
+                        <TextView
+                            android:id="@+id/wifi_toggle_title"
+                            android:text="@string/turn_on_wifi"
+                            android:textDirection="locale"
+                            android:layout_width="wrap_content"
+                            android:layout_height="match_parent"
+                            android:gravity="start|center_vertical"
+                            android:textColor="?android:attr/textColorPrimary"
+                            android:textSize="16sp"
+                            android:fontFamily="google-sans"/>
+                    </FrameLayout>
+
+                    <FrameLayout
+                        android:layout_width="@dimen/settingslib_switch_track_width"
+                        android:layout_height="48dp"
+                        android:layout_marginTop="10dp"
+                        android:layout_marginBottom="10dp">
+                        <Switch
+                            android:id="@+id/wifi_toggle"
+                            android:switchMinWidth="@dimen/settingslib_switch_track_width"
+                            android:layout_gravity="center"
+                            android:layout_width="@dimen/settingslib_switch_track_width"
+                            android:layout_height="@dimen/settingslib_switch_track_height"
+                            android:track="@drawable/settingslib_track_selector"
+                            android:thumb="@drawable/settingslib_thumb_selector"
+                            android:theme="@style/MainSwitch.Settingslib"/>
+                    </FrameLayout>
+
+                </LinearLayout>
+
+                <LinearLayout
+                    android:id="@+id/wifi_connected_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="72dp"
+                    android:layout_gravity="center_vertical|start"
+                    android:clickable="true"
+                    android:focusable="true"
+                    android:visibility="gone"
+                    android:background="?android:attr/selectableItemBackground"
+                    android:orientation="horizontal"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                    android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+                    android:paddingStart="20dp"
+                    android:paddingEnd="24dp">
+
+                    <FrameLayout
+                        android:layout_width="24dp"
+                        android:layout_height="24dp"
+                        android:clickable="false"
+                        android:layout_gravity="center_vertical|start">
+                        <ImageView
+                            android:id="@+id/wifi_connected_icon"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"/>
+                    </FrameLayout>
+
+                    <LinearLayout
+                        android:id="@+id/wifi_connected_list"
+                        android:orientation="vertical"
+                        android:clickable="false"
+                        android:layout_width="wrap_content"
+                        android:layout_height="72dp"
+                        android:layout_marginEnd="30dp"
+                        android:layout_weight="1"
+                        android:gravity="start|center_vertical">
+                        <TextView
+                            android:id="@+id/wifi_connected_title"
+                            android:textDirection="locale"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center_vertical|start"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                            android:ellipsize="end"
+                            android:textColor="?android:attr/textColorPrimary"
+                            android:textSize="14sp"
+                            android:fontFamily="google-sans"/>
+                        <TextView
+                            android:id="@+id/wifi_connected_summary"
+                            android:textDirection="locale"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center_vertical|start"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                            android:ellipsize="end"
+                            android:textColor="?android:attr/textColorTertiary"
+                            android:textSize="14sp"
+                            android:fontFamily="google-sans"/>
+                    </LinearLayout>
+
+                    <FrameLayout
+                        android:layout_width="24dp"
+                        android:layout_height="match_parent"
+                        android:clickable="false"
+                        android:layout_gravity="end|center_vertical"
+                        android:gravity="center">
+                        <ImageView
+                            android:id="@+id/wifi_settings_icon"
+                            android:src="@drawable/ic_settings_24dp"
+                            android:layout_width="24dp"
+                            android:layout_gravity="end|center_vertical"
+                            android:layout_height="wrap_content"/>
+                    </FrameLayout>
+
+                </LinearLayout>
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/wifi_list_layout"
+                    android:scrollbars="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:overScrollMode="never"
+                    android:nestedScrollingEnabled="false"/>
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/see_all_layout"
+                android:layout_width="match_parent"
+                android:layout_height="64dp"
+                android:clickable="true"
+                android:focusable="true"
+                android:background="?android:attr/selectableItemBackground"
+                android:gravity="center_vertical|center_horizontal"
+                android:orientation="horizontal"
+                android:paddingStart="22dp"
+                android:paddingEnd="22dp">
+
+                <FrameLayout
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:clickable="false"
+                    android:layout_gravity="center_vertical|start"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
+                    <ImageView
+                        android:id="@+id/arrow_forward"
+                        android:src="@drawable/ic_arrow_forward"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center"/>
+                </FrameLayout>
+
+                <FrameLayout
+                    android:orientation="vertical"
+                    android:clickable="false"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
+                    <TextView
+                        android:text="@string/see_all_networks"
+                        android:textDirection="locale"
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent"
+                        android:gravity="start|center_vertical"
+                        android:textColor="?android:attr/textColorPrimary"
+                        android:textSize="14sp"
+                        android:fontFamily="google-sans"/>
+                </FrameLayout>
+
+            </LinearLayout>
+
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="48dp"
+                android:layout_marginBottom="40dp">
+                <Button
+                    style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                    android:id="@+id/done"
+                    android:layout_width="67dp"
+                    android:layout_height="36dp"
+                    android:layout_marginEnd="24dp"
+                    android:layout_gravity="end|center_vertical"
+                    android:background="@drawable/internet_dialog_footer_background"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:text="@string/inline_done_button"
+                    android:textSize="14sp"
+                    android:fontFamily="google-sans"/>
+            </FrameLayout>
+        </LinearLayout>
+    </androidx.core.widget.NestedScrollView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml
new file mode 100644
index 0000000..b52933d
--- /dev/null
+++ b/packages/SystemUI/res/layout/internet_list_item.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/internet_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/wifi_list"
+        android:layout_width="match_parent"
+        android:layout_height="72dp"
+        android:layout_gravity="center_vertical|start"
+        android:clickable="true"
+        android:focusable="true"
+        android:background="?android:attr/selectableItemBackground"
+        android:orientation="horizontal"
+        android:paddingStart="20dp"
+        android:paddingEnd="40dp">
+        <FrameLayout
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:clickable="false"
+            android:layout_gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
+            <ImageView
+                android:id="@+id/wifi_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"/>
+        </FrameLayout>
+
+        <LinearLayout
+            android:id="@+id/wifi_network_layout"
+            android:orientation="vertical"
+            android:clickable="false"
+            android:layout_width="wrap_content"
+            android:layout_height="72dp"
+            android:layout_weight="1"
+            android:gravity="start|center_vertical"
+            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
+            <TextView
+                android:id="@+id/wifi_title"
+                android:textDirection="locale"
+                android:layout_width="wrap_content"
+                android:layout_height="20dp"
+                android:gravity="start|center_vertical"
+                android:ellipsize="end"
+                android:textColor="?android:attr/textColorPrimary"
+                android:textSize="14sp"
+                android:fontFamily="google-sans"
+                android:layout_marginEnd="18dp"/>
+            <TextView
+                android:id="@+id/wifi_summary"
+                android:textDirection="locale"
+                android:layout_width="wrap_content"
+                android:layout_height="20dp"
+                android:gravity="start|center_vertical"
+                android:ellipsize="end"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textSize="14sp"
+                android:fontFamily="google-sans"
+                android:layout_marginEnd="18dp"/>
+        </LinearLayout>
+
+        <FrameLayout
+            android:layout_width="24dp"
+            android:layout_height="match_parent"
+            android:clickable="false"
+            android:layout_gravity="end|center_vertical">
+            <ImageView
+                android:id="@+id/wifi_locked_icon"
+                android:layout_gravity="end|center_vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+        </FrameLayout>
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 5b9ca1b..966f992 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -26,17 +26,38 @@
     android:focusable="true"
     android:theme="@style/Theme.SystemUI.QuickSettings.Header">
 
-    <com.android.systemui.statusbar.policy.Clock
-        android:id="@+id/clock"
+    <LinearLayout
+        android:id="@+id/clock_container"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:minWidth="48dp"
-        android:minHeight="48dp"
+        android:orientation="horizontal"
+        android:layout_gravity="center_vertical|start"
         android:gravity="center_vertical|start"
-        android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
-        android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
-        android:singleLine="true"
-        android:textAppearance="@style/TextAppearance.QS.Status" />
+        >
+
+        <com.android.systemui.statusbar.policy.Clock
+            android:id="@+id/clock"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:minWidth="48dp"
+            android:minHeight="48dp"
+            android:gravity="center_vertical|start"
+            android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
+            android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.QS.Status" />
+
+        <com.android.systemui.statusbar.policy.VariableDateView
+            android:id="@+id/date_clock"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical|start"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.QS.Status"
+            systemui:longDatePattern="@string/abbrev_wday_month_day_no_year_alarm"
+            systemui:shortDatePattern="@string/abbrev_month_day_no_year"
+        />
+    </LinearLayout>
 
     <include layout="@layout/qs_carrier_group"
         android:id="@+id/carrier_group"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index bff93a9..cc44b5e 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -36,7 +36,7 @@
         android:layout_weight="1"
         android:gravity="center_vertical|start" >
 
-        <com.android.systemui.statusbar.policy.DateView
+        <com.android.systemui.statusbar.policy.VariableDateView
             android:id="@+id/date"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -44,7 +44,9 @@
             android:gravity="center_vertical"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.QS.Status"
-            systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
+            systemui:longDatePattern="@string/abbrev_wday_month_day_no_year_alarm"
+            systemui:shortDatePattern="@string/abbrev_month_day_no_year"
+        />
     </FrameLayout>
 
     <android.widget.Space
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index bea50e8..71e8fc9 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -62,8 +62,7 @@
     <com.android.systemui.statusbar.LightRevealScrim
             android:id="@+id/light_reveal_scrim"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="gone" />
+            android:layout_height="match_parent" />
 
     <include layout="@layout/status_bar_expanded"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 8229661..b88962d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoem om skerm te vul"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Strek om skerm te vul"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock is gedeaktiveer"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Stoor tans skermkiekie..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7f101d7..1110c99 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ማያ እንዲሞላ አጉላ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ማያ ለመሙለት ሳብ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ተሰናክሏል"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8f230246..6d66748 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"تكبير/تصغير لملء الشاشة"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"توسيع بملء الشاشة"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"لقطة شاشة"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏تم إيقاف Smart Lock."</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"جارٍ حفظ لقطة الشاشة..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index c4438fc..ee9ae88 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্ৰীণ পূর্ণ কৰিবলৈ জুম কৰক"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"স্ক্ৰীণ পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock অক্ষম কৰা হৈছে"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 7e50b19..6779834 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock deaktivdir"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 701765f..607391a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj na celom ekranu"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci na ceo ekran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock je onemogućen"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Čuvanje snimka ekrana..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 5da6cf8..d4954c1 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Павял. на ўвесь экран"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Расцягн. на ўвесь экран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функцыя \"Smart Lock\" адключана"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Захаванне скрыншота..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 742de25..b938880 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Мащаб – запълва екрана"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Разпъване – запълва екрана"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Екранна снимка"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функцията Smart Lock е деактивирана"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Екранната снимка се запазва..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index b35ae1f..811b6a5 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট নিন"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index b877397..d326a51 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Uvećaj prikaz na ekran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci prikaz na ekran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock je onemogućen"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spašavanje snimka ekrana..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a5504f0..4315057 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per omplir pantalla"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estira per omplir pant."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock desactivat"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"S\'està desant captura de pantalla..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f48c9fb..1cac5f7 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Přiblížit na celou obrazovku"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Na celou obrazovku"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funkce Smart Lock je deaktivována"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ukládání snímku obrazovky..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index cbef464..48f8086 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom til fuld skærm"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stræk til fuld skærm"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock er deaktiveret"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gemmer screenshot..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 50fcdfb..4c4a876 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom auf Bildschirmgröße"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Auf Bildschirmgröße anpassen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock deaktiviert"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"Bild gesendet"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot wird gespeichert..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot wird gespeichert..."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index b8d357f..0b37ed8 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ζουμ σε πλήρη οθόνη"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Προβoλή σε πλήρη οθ."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Το Smart Lock έχει απενεργοποιηθεί"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Αποθήκ. στιγμιότυπου οθόνης..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d69a95b..e50c00e 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3666069..fba313e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d69a95b..e50c00e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d69a95b..e50c00e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 030c588..a42a531 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎Zoom to fill screen‎‏‎‎‏‎"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎Stretch to fill screen‎‏‎‎‏‎"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎Screenshot‎‏‎‎‏‎"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎Smart Lock disabled‎‏‎‎‏‎"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎sent an image‎‏‎‎‏‎"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎Saving screenshot…‎‏‎‎‏‎"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎Saving screenshot…‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index bb43d81..9929020 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ocupar la pantalla"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estirar p/ ocupar la pantalla"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Se inhabilitó Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura de pantalla"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index fd0f865..6a42460 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ajustar"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Expandir para ajustar"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock inhabilitado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 6cd609f..10becfb 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Suumi ekraani täitmiseks"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Venita ekraani täitmiseks"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock on keelatud"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Kuvatõmmise salvestamine ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b6162a8..3dbbc07 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Handiagotu pantaila betetzeko"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Luzatu pantaila betetzeko"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Desgaitu da Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Pantaila-argazkia gordetzen…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d1ddd8c..4606ae7 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"بزرگ‌نمایی برای پر کردن صفحه"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"گسترده کردن برای پر کردن صفحه"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"نماگرفت"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏Smart Lock غیرفعال شد"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"تصویری ارسال کرد"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"در حال ذخیره نماگرفت..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"درحال ذخیره نماگرفت…"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 652acf7..9d9b152 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoomaa koko näyttöön"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Venytä koko näyttöön"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock poistettu käytöstä"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Tallennetaan kuvakaappausta..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1ec1f91..22e77a0 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 6a08d87..5510ef1 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock désactivé"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 15678e4..a9f0593 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock está desactivado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 9255827..9f05de5 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"સ્ક્રીન ભરવા માટે ઝૂમ કરો"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"સ્ક્રીન ભરવા માટે ખેંચો"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1ebb517..ffe3a5b 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"स्‍क्रीन भरने के लिए ज़ूम करें"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"स्‍क्रीन भरने के लिए खींचें"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock की सुविधा बंद कर दी गई है"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9ec657d..260dba9 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj i ispuni zaslon"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rastegni i ispuni zaslon"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snimka zaslona"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock onemogućen"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spremanje snimke zaslona..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index d9d8148..4a71826 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Nagyítás a kitöltéshez"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Nyújtás kitöltéshez"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock kikapcsolva"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Képernyőkép mentése..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 1d8094a..bdebdad 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Խոշորացնել` էկրանը լցնելու համար"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ձգել` էկրանը լցնելու համար"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock-ն անջատված է"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Սքրինշոթը պահվում է…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 76ee722..15b64c6 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Perbesar utk mengisi layar"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rentangkn utk mngisi layar"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dinonaktifkan"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan screenshot..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0190554..e0ff373 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Fylla skjá með aðdrætti"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Teygja yfir allan skjáinn"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Slökkt á Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Vistar skjámynd…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0efab5c..3d26cbb 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per riempire schermo"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funzionalità Smart Lock disattivata"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot…"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 1e4c9d6..ed1ea36 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"הגדלת התצוגה למילוי המסך"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"מתיחה למילוי של המסך"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"צילום המסך נשמר..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"המערכת שומרת את צילום המסך..."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2725979..502f962 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"画面サイズに合わせて拡大"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"画面サイズに合わせて拡大"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock は無効です"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"スクリーンショットを保存中..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 21e1c52..38c59bf 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"გაწიეთ ეკრანის შესავსებად."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock გათიშულია"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"სკრინშოტის შენახვა…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 6a9a9b5..afb46e8 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Экранды толтыру үшін ұлғайту"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтыру үшін созу"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock өшірілді"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншотты сақтауда…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 080ba19..9f4ddf3 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ពង្រីក​​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ទាញ​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"បានបិទ Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បាន​ផ្ញើរូបភាព"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index f63d02f..36d3d7d 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 371b7de..a846bc1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"전체화면 모드로 확대"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"전체화면 모드로 확대"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 사용 중지됨"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"캡쳐화면 저장 중..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 404b9ac..124dc53 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Экрнд тлтр ү. чен өлч өзг"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтуруу ү-н чоюу"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock өчүрүлдү"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншот сакталууда…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 33fddef..c27394c 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ປິດການນຳໃຊ້ Smart Lock ແລ້ວ"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 94faaf4..a1cd602 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Keisti mast., kad atit. ekr."</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ištempti, kad atit. ekr."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrano kopija"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"„Smart Lock“ išjungta"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Išsaugoma ekrano kopija..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 0d14405..b0da7f7 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Tālumm., lai aizp. ekr."</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stiepiet, lai aizp. ekr."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrānuzņēmums"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Sistēma Smart Lock ir atspējota"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saglabā ekrānuzņēmumu…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 5fda8b2..bee9bff 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај да се исполни екранот"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Растегни да се исполни екранот"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Слика од екранот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Оневозможено е Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"испрати слика"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сликата на екранот се зачувува..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Сликата на екранот се зачувува..."</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6956934..061f43c 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0d1ad4b..8bf0dbc 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Дэлгэц дүүргэх бол өсгөнө үү"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Дэлгэц дүүргэх бол татна уу"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Ухаалаг түгжээг идэвхгүй болгосон"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Дэлгэцийн агшинг хадгалж байна…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 1fa1a3e..7d23729 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b7d0246..b662271 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zum untuk memenuhi skrin"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Regang utk memenuhi skrin"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dilumpuhkan"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan tangkapan skrin..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 81d168b..900b98a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ဇူးမ်အပြည့်ဆွဲခြင်း"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ဖန်သားပြင်အပြည့်ဆန့်ခြင်း"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ပိတ်ထားသည်"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ဖန်သားပြင်ဓါတ်ပုံသိမ်းစဉ်.."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 360c58b..938234d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom for å fylle skjermen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Strekk for å fylle skjerm"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock er slått av"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Lagrer skjermdumpen …"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e5787b5..440e8af 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7d75b6e..66ec98a 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom om scherm te vullen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rek uit v. schermvulling"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock staat uit"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"heeft een afbeelding gestuurd"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot opslaan..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot opslaan..."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ee524bf..f76adfa 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ସ୍କ୍ରୀନ୍‌କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍‌ସଟ୍ ନିଅନ୍ତୁ"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index d68ab4f..9d1edfa 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 9aade18..b6412e7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Powiększ, aby wypełnić ekran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rozciągnij, aby wypełnić ekran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Wyłączono Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Zapisywanie zrzutu ekranu..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index cab482a..7c3f864 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"O Smart Lock foi desativado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index eec3468..df48773 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para preencher o ecrã"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Esticar p. caber em ec. int."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock desativado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"A guardar captura de ecrã..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index cab482a..7c3f864 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"O Smart Lock foi desativado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 1e30ea7..c36f7e7 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom pt. a umple ecranul"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Înt. pt. a umple ecranul"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dezactivat"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Se salv. captura de ecran..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 99465d5..cc63a91 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Подогнать по размерам экрана"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Растянуть на весь экран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функция Smart Lock отключена."</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сохранение..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 6ea2a0d..c08d6f7 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"තිරය පිරවීමට විශාලනය කරන්න"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"තිරය පිරවීමට අදින්න"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"තිර රුව"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock අබලයි"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"තිර රුව සුරකිමින්…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 399b979..0aabf7c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Priblížiť na celú obrazovku"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Na celú obrazovku"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funkcia Smart Lock je deaktivovaná"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Prebieha ukladanie snímky obrazovky..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 0c93bce..ecf5ca7 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Povečava čez cel zaslon"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Raztegnitev čez zaslon"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Storitev Smart Lock je onemogočena."</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Shranjev. posnetka zaslona ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 7f101db..86bd5a1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1da42cf..83317d2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај на целом екрану"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Развуци на цео екран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Снимак екрана"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock је онемогућен"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Чување снимка екрана..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 05aeffb..86b0fc7 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zooma för att fylla skärm"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Dra för att fylla skärmen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skärmbild"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock har inaktiverats"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skärmbilden sparas ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmbilden sparas ..."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 7f51e826..58401b5 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Kuza ili kujaza skrini"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Tanua ili kujaza skrini"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Kipengele cha Smart Lock kimezimwa"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index da80b85..0a34dfd 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -95,4 +95,7 @@
     <dimen name="controls_top_margin">24dp</dimen>
 
     <dimen name="global_actions_grid_item_layout_height">80dp</dimen>
+
+    <!-- Internet panel related dimensions -->
+    <dimen name="internet_dialog_list_max_width">624dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a16355e..efb704f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"திரையை நிரப்ப அளவை மாற்று"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"திரையை நிரப்ப இழு"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock முடக்கப்பட்டது"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index eeeaf0d..6546059 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -77,6 +77,8 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్‌కు నింపేలా జూమ్ చేయండి"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్‌కు నింపేలా విస్తరించండి"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్‌షాట్"</string>
+    <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
+    <skip />
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్‌ను పంపారు"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 1fd1313..df358a3 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ขยายจนเต็มหน้าจอ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ยืดจนเต็มหน้าจอ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ปิดใช้ Smart Lock แล้ว"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"กำลังบันทึกภาพหน้าจอ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3837364..a74345d 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"I-zoom upang punan screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"I-stretch upang mapuno screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Naka-disable ang Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nagpadala ng larawan"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Sine-save ang screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Sine-save ang screenshot…"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 1cd547c..51e32458 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Yakınlaştır (ekranı kaplasın)"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Genişlet (ekran kapansın)"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock devre dışı"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ekran görüntüsü kaydediliyor..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 70922aa..b1febf5 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Масштабув. на весь екран"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Розтягнути на весь екран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock вимкнено"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Збереження знімка екрана..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 7ef0149..fcb53a4 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"پوری سکرین پر زوم کریں"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"پوری سکرین پر پھیلائیں"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏Smart Lock کو غیر فعال کیا گیا"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 08ac980..7822b84 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ekranga moslashtirish"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ekran hajmida cho‘zish"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock faolsizlantirildi"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"rasm yuborildi"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinshot saqlanmoqda…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinshot saqlanmoqda…"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 60b1232..5a1ea4c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"T.phóng để lấp đầy m.hình"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Giãn ra để lấp đầy m.hình"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Tính năng Smart Lock đã tắt"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Đang lưu ảnh chụp màn hình..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 6c6c35f..b1968ee 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"缩放以填满屏幕"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"拉伸以填满屏幕"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在保存屏幕截图..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f8ede3a..7c048ea 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"已傳送圖片"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕擷取畫面..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕擷取畫面..."</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index df84fb0..8647aed 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"傳送了一張圖片"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕截圖…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕截圖…"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index fe97daa..b0c8121 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Sondeza ukugcwalisa isikrini"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Nweba ukugcwalisa isikrini"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Isithombe-skrini"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Ukhiye oSmathi ukhutshaziwe"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ilondoloz umfanekiso weskrini..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index b5337d3..3121ce3 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -69,6 +69,10 @@
     <declare-styleable name="DateView">
         <attr name="datePattern" format="string" />
     </declare-styleable>
+    <declare-styleable name="VariableDateView">
+        <attr name="longDatePattern" format="string" />
+        <attr name="shortDatePattern" format="string" />
+    </declare-styleable>
     <declare-styleable name="PseudoGridView">
         <attr name="numColumns" format="integer" />
         <attr name="verticalSpacing" format="dimension" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 2260d21..a4c1d94 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 -->
-<resources>
+<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <drawable name="notification_number_text_color">#ffffffff</drawable>
     <drawable name="ticker_background_color">#ff1d1d1d</drawable>
     <drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
@@ -281,4 +281,16 @@
     <color name="wallet_card_border">#33FFFFFF</color>
 
     <color name="people_tile_background">@android:color/system_accent2_50</color>
+
+    <!-- Internet Dialog -->
+    <!-- Material next state on color-->
+    <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
+    <!-- Material next state off color-->
+    <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
+    <!-- Material next track on color-->
+    <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
+    <!-- Material next track off color-->
+    <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
+    <color name="connected_network_primary_color">#191C18</color>
+    <color name="connected_network_secondary_color">#41493D</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d274c91..b6d5b3a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -194,6 +194,11 @@
      low powered state yet. -->
     <bool name="doze_long_press_uses_prox">true</bool>
 
+    <!-- Doze: whether the brightness sensor uses the proximity sensor.
+     If both this parameter and doze_selectively_register_prox are true, registration for the
+     brightness sensor won't occur when the display state is ON. -->
+    <bool name="doze_brightness_uses_prox">true</bool>
+
     <!-- Doze: should notifications be used as a pulse signal? -->
     <bool name="doze_pulse_on_notifications">true</bool>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 78db2a8..ac7ad5d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1590,4 +1590,42 @@
     <!-- The padding between the icon and the text. -->
     <dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
     <dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
+
+    <!-- Internet panel related dimensions -->
+    <dimen name="internet_dialog_list_margin">12dp</dimen>
+    <dimen name="internet_dialog_list_max_height">646dp</dimen>
+    <dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen>
+
+    <!-- Signal icon in internet dialog -->
+    <dimen name="signal_strength_icon_size">24dp</dimen>
+
+    <!-- Internet dialog related dimensions -->
+    <dimen name="internet_dialog_corner_radius">24dp</dimen>
+    <!-- End margin of network layout -->
+    <dimen name="internet_dialog_network_layout_margin">16dp</dimen>
+    <!-- Size of switch bar in internet dialog -->
+    <dimen name="settingslib_switchbar_margin">16dp</dimen>
+    <!-- Minimum width of switch -->
+    <dimen name="settingslib_min_switch_width">52dp</dimen>
+    <!-- Size of layout margin left -->
+    <dimen name="settingslib_switchbar_padding_left">20dp</dimen>
+    <!-- Size of layout margin right -->
+    <dimen name="settingslib_switchbar_padding_right">20dp</dimen>
+    <!-- Radius of switch bar -->
+    <dimen name="settingslib_switch_bar_radius">35dp</dimen>
+    <!-- Margin of switch thumb -->
+    <dimen name="settingslib_switch_thumb_margin">4dp</dimen>
+    <!-- Size of switch thumb -->
+    <dimen name="settingslib_switch_thumb_size">20dp</dimen>
+    <!-- Width of switch track -->
+    <dimen name="settingslib_switch_track_width">52dp</dimen>
+    <!-- Height of switch track -->
+    <dimen name="settingslib_switch_track_height">28dp</dimen>
+    <!-- Radius of switch track -->
+    <dimen name="settingslib_switch_track_radius">35dp</dimen>
+
+    <!-- Height percentage of the parent container occupied by the communal view -->
+    <item name="communal_source_height_percentage" format="float" type="dimen">0.80</item>
+
+    <dimen name="drag_and_drop_icon_size">70dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a670216..a180cc1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -211,6 +211,8 @@
 
     <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]-->
     <string name="global_action_screenshot">Screenshot</string>
+    <!-- Message shown in power menu when smart lock has been disabled [CHAR_LIMIT=NONE] -->
+    <string name="global_action_smart_lock_disabled">Smart Lock disabled</string>
 
     <!-- text to show in place of RemoteInput images when they cannot be shown.
          [CHAR LIMIT=50] -->
@@ -2992,4 +2994,39 @@
     <string name="global_actions_change_description" translatable="false"><xliff:g>%1$s</xliff:g></string>
     <!-- URL for more information about changes in global actions -->
     <string name="global_actions_change_url" translatable="false"></string>
+
+    <!-- Provider Model: Title of the airplane mode in the internet dialog. [CHAR LIMIT=50] -->
+    <string name="airplane_mode">Airplane mode</string>
+    <!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] -->
+    <string name="mobile_data_settings_title">Mobile data</string>
+    <!-- Provider Model: Summary text separator for preferences including a short description
+         (eg. "Connected / 5G"). [CHAR LIMIT=50] -->
+    <string name="preference_summary_default_combination"><xliff:g id="state" example="Connected">%1$s</xliff:g> / <xliff:g id="networkMode" example="LTE">%2$s</xliff:g></string>
+    <!-- Provider Model:
+         Summary indicating that a SIM has an active mobile data connection [CHAR LIMIT=50] -->
+    <string name="mobile_data_connection_active">Connected</string>
+    <!-- Provider Model:
+     Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] -->
+    <string name="mobile_data_off_summary">Internet won\u0027t auto\u2011connect</string>
+    <!-- Provider Model:
+     Summary indicating that a active SIM and no network available [CHAR LIMIT=50] -->
+    <string name="mobile_data_no_connection">No connection</string>
+    <!-- Provider Model: Summary indicating that no other networks available [CHAR LIMIT=50] -->
+    <string name="non_carrier_network_unavailable">No other networks available</string>
+    <!-- Provider Model: Summary indicating that no networks available [CHAR LIMIT=50] -->
+    <string name="all_network_unavailable">No networks available</string>
+    <!-- Provider Model: Panel title text for turning on the Wi-Fi networks. [CHAR LIMIT=40] -->
+    <string name="turn_on_wifi">Wi\u2011Fi</string>
+    <!-- Provider Model: Title for detail page of wifi network [CHAR LIMIT=30] -->
+    <string name="pref_title_network_details" msgid="7329759534269363308">"Network details"</string>
+    <!-- Provider Model: Panel subtitle for tapping a network to connect to internet. [CHAR LIMIT=60] -->
+    <string name="tap_a_network_to_connect">Tap a network to connect</string>
+    <!-- Provider Model: Panel subtitle for unlocking screen to view networks. [CHAR LIMIT=60] -->
+    <string name="unlock_to_view_networks">Unlock to view networks</string>
+    <!-- Provider Model: Wi-Fi settings. text displayed when Wi-Fi is on and network list is empty [CHAR LIMIT=50]-->
+    <string name="wifi_empty_list_wifi_on">Searching for networks\u2026</string>
+    <!-- Provider Model: Failure notification for connect -->
+    <string name="wifi_failed_connect_message">Failed to connect to network</string>
+    <!-- Provider Model: Title to see all the networks [CHAR LIMIT=50] -->
+    <string name="see_all_networks">See all</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 51eabf6..d254742 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -903,4 +903,52 @@
       <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen.  -->
       <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
     </style>
+
+    <style name="Animation.InternetDialog" parent="@android:style/Animation.InputMethod">
+    </style>
+
+    <style name="Widget.SliceView.Panel">
+        <item name="titleSize">16sp</item>
+        <item name="rowStyle">@style/SliceRow</item>
+        <item name="android:background">?android:attr/colorBackgroundFloating</item>
+    </style>
+
+    <style name="SliceRow">
+        <!-- 2dp start padding for the start icon -->
+        <item name="titleItemStartPadding">2dp</item>
+        <item name="titleItemEndPadding">0dp</item>
+
+        <!-- Padding between content and the start icon is 14dp -->
+        <item name="contentStartPadding">14dp</item>
+        <!-- Padding between content and end items is 16dp -->
+        <item name="contentEndPadding">16dp</item>
+
+        <!-- Both side margins of end item are 16dp -->
+        <item name="endItemStartPadding">16dp</item>
+        <item name="endItemEndPadding">16dp</item>
+
+        <!-- Both side margins of bottom divider are 12dp -->
+        <item name="bottomDividerStartPadding">12dp</item>
+        <item name="bottomDividerEndPadding">12dp</item>
+
+        <item name="actionDividerHeight">32dp</item>
+    </style>
+
+    <style name="Theme.SystemUI.Dialog.Internet">
+        <item name="android:windowBackground">@drawable/internet_dialog_background</item>
+    </style>
+
+    <style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
+    </style>
+
+    <style name="TrimmedHorizontalProgressBar"
+           parent="android:Widget.Material.ProgressBar.Horizontal">
+        <item name="android:indeterminateDrawable">
+            @drawable/progress_indeterminate_horizontal_material_trimmed
+        </item>
+        <item name="android:minHeight">4dp</item>
+        <item name="android:maxHeight">4dp</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index edb05691..dd3bb89 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -27,6 +27,7 @@
 import android.widget.ImageView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
@@ -79,7 +80,11 @@
         mLockIcon.setImageDrawable(drawable);
     }
 
-    void setCenterLocation(@NonNull PointF center, int radius) {
+    /**
+     * Set the location of the lock icon.
+     */
+    @VisibleForTesting
+    public void setCenterLocation(@NonNull PointF center, int radius) {
         mLockIconCenter = center;
         mRadius = radius;
 
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 509ac8a..47f0714 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -46,6 +46,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.AuthRippleController;
 import com.android.systemui.biometrics.UdfpsController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
@@ -67,7 +68,8 @@
 /**
  * Controls when to show the LockIcon affordance (lock/unlocked icon or circle) on lock screen.
  *
- * This view will only be shown if the user has UDFPS or FaceAuth enrolled
+ * For devices with UDFPS, the lock icon will show at the sensor location. Else, the lock
+ * icon will show a set distance from the bottom of the device.
  */
 @StatusBarComponent.StatusBarScope
 public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
@@ -99,6 +101,7 @@
     @NonNull private CharSequence mUnlockedLabel;
     @NonNull private CharSequence mLockedLabel;
     @Nullable private final Vibrator mVibrator;
+    @Nullable private final AuthRippleController mAuthRippleController;
 
     private boolean mIsDozing;
     private boolean mIsBouncerShowing;
@@ -135,7 +138,8 @@
             @NonNull AccessibilityManager accessibilityManager,
             @NonNull ConfigurationController configurationController,
             @NonNull @Main DelayableExecutor executor,
-            @Nullable Vibrator vibrator
+            @Nullable Vibrator vibrator,
+            @Nullable AuthRippleController authRippleController
     ) {
         super(view);
         mStatusBarStateController = statusBarStateController;
@@ -148,6 +152,7 @@
         mConfigurationController = configurationController;
         mExecutor = executor;
         mVibrator = vibrator;
+        mAuthRippleController = authRippleController;
 
         final Context context = view.getContext();
         mUnlockIcon = mView.getContext().getResources().getDrawable(
@@ -168,15 +173,14 @@
 
     @Override
     protected void onInit() {
+        mAuthController.addCallback(mAuthControllerCallback);
+        mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+
         mView.setAccessibilityDelegate(mAccessibilityDelegate);
     }
 
     @Override
     protected void onViewAttached() {
-        // we check this here instead of onInit since the FingerprintManager + FaceManager may not
-        // have started up yet onInit
-        mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
-
         updateConfiguration();
         updateKeyguardShowing();
         mUserUnlockedWithBiometric = false;
@@ -538,6 +542,9 @@
 
                     // pre-emptively set to true to hide view
                     mIsBouncerShowing = true;
+                    if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
+                        mAuthRippleController.showRipple(FINGERPRINT);
+                    }
                     updateVisibility();
                     mKeyguardViewController.showBouncer(/* scrim */ true);
                 }
@@ -577,4 +584,12 @@
     public void setAlpha(float alpha) {
         mView.setAlpha(alpha);
     }
+
+    private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
+        @Override
+        public void onAllAuthenticatorsRegistered() {
+            mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+            updateConfiguration();
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 76f30a8..00b33a4 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -65,6 +65,7 @@
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.qs.ReduceBrightColorsController;
+import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.screenrecord.RecordingController;
@@ -364,6 +365,7 @@
     @Inject Lazy<UiEventLogger> mUiEventLogger;
     @Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
     @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
+    @Inject Lazy<InternetDialogFactory> mInternetDialogFactory;
 
     @Inject
     public Dependency() {
@@ -578,6 +580,7 @@
         mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get);
         mProviders.put(EdgeBackGestureHandler.Factory.class,
                 mEdgeBackGestureHandlerFactoryLazy::get);
+        mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get);
         mProviders.put(UiEventLogger.class, mUiEventLogger::get);
         mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
         mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get);
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index affad7a..8c63f7b 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -438,6 +438,12 @@
             private boolean mCancelled;
 
             @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                mCallback.onBeginDrag(animView);
+            }
+
+            @Override
             public void onAnimationCancel(Animator animation) {
                 mCancelled = true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
index 81a13a2..4082015 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
@@ -57,7 +57,9 @@
         public void run() {
             mView.removeCallbacks(this);
             mView.show(false /* show */, true /* animate */, () -> {
-                mWindowManager.removeView(mView);
+                if (mView.isAttachedToWindow()) {
+                    mWindowManager.removeView(mView);
+                }
             });
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
index c9e6771..5616a00 100644
--- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
@@ -40,10 +40,10 @@
  * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
  * indicating that restoring is finished for a given user.
  */
-class BackupHelper : BackupAgentHelper() {
+open class BackupHelper : BackupAgentHelper() {
 
     companion object {
-        private const val TAG = "BackupHelper"
+        const val TAG = "BackupHelper"
         internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
         private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
         private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 0ce1846..ab5f2b828 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -786,7 +786,11 @@
                 .build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
     }
 
-    interface Callback {
+    /**
+     * AuthController callback used to receive signal for when biometric authenticators are
+     * registered.
+     */
+    public interface Callback {
         /**
          * Called when authenticators are registered. If authenticators are already
          * registered before this call, this callback will never be triggered.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2de489d..b8c15d8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -43,7 +43,6 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.Trace;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -76,6 +75,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
+import com.android.systemui.util.time.SystemClock;
 
 import java.util.Optional;
 
@@ -125,6 +125,7 @@
     @Nullable private final UdfpsHbmProvider mHbmProvider;
     @NonNull private final KeyguardBypassController mKeyguardBypassController;
     @NonNull private final ConfigurationController mConfigurationController;
+    @NonNull private final SystemClock mSystemClock;
     @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
@@ -449,19 +450,19 @@
                         final String touchInfo = String.format(
                                 "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
                                 minor, major, v, exceedsVelocityThreshold);
-                        final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
+                        final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
                         if (!isIlluminationRequested && !mGoodCaptureReceived &&
                                 !exceedsVelocityThreshold) {
                             onFingerDown((int) event.getRawX(), (int) event.getRawY(), minor,
                                     major);
                             Log.v(TAG, "onTouch | finger down: " + touchInfo);
-                            mTouchLogTime = SystemClock.elapsedRealtime();
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(),
+                            mTouchLogTime = mSystemClock.elapsedRealtime();
+                            mPowerManager.userActivity(mSystemClock.uptimeMillis(),
                                     PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
                             handled = true;
                         } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
                             Log.v(TAG, "onTouch | finger move: " + touchInfo);
-                            mTouchLogTime = SystemClock.elapsedRealtime();
+                            mTouchLogTime = mSystemClock.elapsedRealtime();
                         }
                     } else {
                         Log.v(TAG, "onTouch | finger outside");
@@ -525,7 +526,8 @@
             @NonNull KeyguardBypassController keyguardBypassController,
             @NonNull DisplayManager displayManager,
             @Main Handler mainHandler,
-            @NonNull ConfigurationController configurationController) {
+            @NonNull ConfigurationController configurationController,
+            @NonNull SystemClock systemClock) {
         mContext = context;
         mExecution = execution;
         // TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -561,6 +563,7 @@
                 mainHandler);
         mKeyguardBypassController = keyguardBypassController;
         mConfigurationController = configurationController;
+        mSystemClock = systemClock;
 
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
@@ -703,15 +706,21 @@
         return mCoreLayoutParams;
     }
 
+
     private void onOrientationChanged() {
         // When the configuration changes it's almost always necessary to destroy and re-create
         // the overlay's window to pass it the new LayoutParams.
         // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
         // of whether it is already hidden.
+        final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
         hideUdfpsOverlay();
+
         // If the overlay needs to be shown, this will re-create and show the overlay with the
         // updated LayoutParams. Otherwise, the overlay will remain hidden.
         updateOverlay();
+        if (wasShowingAltAuth) {
+            mKeyguardViewManager.showGenericBouncer(true);
+        }
     }
 
     private void showUdfpsOverlay(@NonNull ServerRequest request) {
@@ -781,6 +790,7 @@
                         mKeyguardViewMediator,
                         mLockscreenShadeTransitionController,
                         mConfigurationController,
+                        mSystemClock,
                         mKeyguardStateController,
                         this
                 );
@@ -817,10 +827,14 @@
             Log.v(TAG, "hideUdfpsOverlay | removing window");
             // Reset the controller back to its starting state.
             onFingerUp();
+            boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
             mWindowManager.removeView(mView);
             mView.setOnTouchListener(null);
             mView.setOnHoverListener(null);
             mView.setAnimationViewController(null);
+            if (wasShowingAltAuth) {
+                mKeyguardViewManager.resetAlternateAuth(true);
+            }
             mAccessibilityManager.removeTouchExplorationStateChangeListener(
                     mTouchExplorationStateChangeListener);
             mView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 3ca7a9f..4a1d883 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.time.SystemClock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -51,6 +52,7 @@
     @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
     @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
     @NonNull private final ConfigurationController mConfigurationController;
+    @NonNull private final SystemClock mSystemClock;
     @NonNull private final KeyguardStateController mKeyguardStateController;
     @NonNull private final UdfpsController mUdfpsController;
 
@@ -61,7 +63,7 @@
     private int mStatusBarState;
     private float mTransitionToFullShadeProgress;
     private float mLastDozeAmount;
-
+    private long mLastUdfpsBouncerShowTime = -1;
     private float mStatusBarExpansion;
     private boolean mLaunchTransitionFadingAway;
 
@@ -84,6 +86,7 @@
             @NonNull KeyguardViewMediator keyguardViewMediator,
             @NonNull LockscreenShadeTransitionController transitionController,
             @NonNull ConfigurationController configurationController,
+            @NonNull SystemClock systemClock,
             @NonNull KeyguardStateController keyguardStateController,
             @NonNull UdfpsController udfpsController) {
         super(view, statusBarStateController, statusBar, dumpManager);
@@ -93,6 +96,7 @@
         mKeyguardViewMediator = keyguardViewMediator;
         mLockScreenShadeTransitionController = transitionController;
         mConfigurationController = configurationController;
+        mSystemClock = systemClock;
         mKeyguardStateController = keyguardStateController;
         mUdfpsController = udfpsController;
     }
@@ -103,6 +107,12 @@
     }
 
     @Override
+    public void onInit() {
+        super.onInit();
+        mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+    }
+
+    @Override
     protected void onViewAttached() {
         super.onViewAttached();
         final float dozeAmount = mStatusBarStateController.getDozeAmount();
@@ -169,6 +179,9 @@
         }
 
         mShowingUdfpsBouncer = show;
+        if (mShowingUdfpsBouncer) {
+            mLastUdfpsBouncerShowTime = mSystemClock.uptimeMillis();
+        }
         updatePauseAuth();
         if (mShowingUdfpsBouncer) {
             if (mStatusBarState == StatusBarState.SHADE_LOCKED) {
@@ -236,16 +249,25 @@
      * If we were previously showing the udfps bouncer, hide it and instead show the regular
      * (pin/pattern/password) bouncer.
      *
-     * Does nothing if we weren't previously showing the udfps bouncer.
+     * Does nothing if we weren't previously showing the UDFPS bouncer.
      */
     private void maybeShowInputBouncer() {
-        if (mShowingUdfpsBouncer) {
+        if (mShowingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) {
             mKeyguardViewManager.showBouncer(true);
             mKeyguardViewManager.resetAlternateAuth(false);
         }
     }
 
     /**
+     * Whether the udfps bouncer has shown for at least 200ms before allowing touches outside
+     * of the udfps icon area to dismiss the udfps bouncer and show the pin/pattern/password
+     * bouncer.
+     */
+    private boolean hasUdfpsBouncerShownWithMinTime() {
+        return (mSystemClock.uptimeMillis() - mLastUdfpsBouncerShowTime) > 200;
+    }
+
+    /**
      * Set the progress we're currently transitioning to the full shade. 0.0f means we're not
      * transitioning yet, while 1.0f means we've fully dragged down.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 470d2f3..98d2739 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -31,6 +31,7 @@
 import android.provider.Settings;
 import android.view.Display;
 
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.dagger.BrightnessSensor;
 import com.android.systemui.doze.dagger.DozeScope;
 import com.android.systemui.doze.dagger.WrappedService;
@@ -63,6 +64,7 @@
     private final Optional<Sensor> mLightSensorOptional;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final DozeParameters mDozeParameters;
+    private final DockManager mDockManager;
     private final int[] mSensorToBrightness;
     private final int[] mSensorToScrimOpacity;
     private final int mScreenBrightnessDim;
@@ -87,7 +89,8 @@
             @BrightnessSensor Optional<Sensor> lightSensorOptional, DozeHost host, Handler handler,
             AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
             WakefulnessLifecycle wakefulnessLifecycle,
-            DozeParameters dozeParameters) {
+            DozeParameters dozeParameters,
+            DockManager dockManager) {
         mContext = context;
         mDozeService = service;
         mSensorManager = sensorManager;
@@ -96,6 +99,7 @@
         mDozeParameters = dozeParameters;
         mDozeHost = host;
         mHandler = handler;
+        mDockManager = dockManager;
 
         mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness;
         mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness;
@@ -122,13 +126,20 @@
 
     @Override
     public void onScreenState(int state) {
-        if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
+        boolean isDockedScreenOn = state == Display.STATE_ON && mDockManager.isDocked();
+        if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND
+                || (isDockedScreenOn && shouldRegisterLightSensorWhenScreenOnDocked())) {
             setLightSensorEnabled(true);
         } else {
             setLightSensorEnabled(false);
         }
     }
 
+    private boolean shouldRegisterLightSensorWhenScreenOnDocked() {
+        return !mDozeParameters.brightnessUsesProx()
+                || !mDozeParameters.getSelectivelyRegisterSensorsUsingProx();
+    }
+
     private void onDestroy() {
         setLightSensorEnabled(false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index b2db86f..55e6154 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -456,13 +456,24 @@
 
         public void updateListening() {
             if (!mConfigured || mSensor == null) return;
-            if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
-                    && !mRegistered) {
-                mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
-                if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered);
+            if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) {
+                if (!mRegistered) {
+                    mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
+                    if (DEBUG) {
+                        Log.d(TAG, "requestTriggerSensor[" + mSensor
+                                + "] " + mRegistered);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "requestTriggerSensor[" + mSensor
+                                + "] already registered");
+                    }
+                }
             } else if (mRegistered) {
                 final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
-                if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt);
+                if (DEBUG) {
+                    Log.d(TAG, "cancelTriggerSensor[" + mSensor + "] " + rt);
+                }
                 mRegistered = false;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index bfa4780..5b327bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -34,7 +34,7 @@
  * See [DumpHandler] for more information on how and when this information is dumped.
  */
 @SysUISingleton
-class DumpManager @Inject constructor() {
+open class DumpManager @Inject constructor() {
     private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
     private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
index 28f63b0..6561bd5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
@@ -25,8 +25,12 @@
  * Proxy to make {@link SystemProperties} easily testable.
  */
 @SysUISingleton
-class SystemPropertiesHelper @Inject constructor() {
+open class SystemPropertiesHelper @Inject constructor() {
     fun getBoolean(name: String, default: Boolean): Boolean {
         return SystemProperties.getBoolean(name, default)
     }
+
+    fun set(name: String, value: Int) {
+        SystemProperties.set(name, value.toString())
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index bc4ced4..1b4a47e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -62,6 +62,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.view.RotationPolicy;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -172,7 +173,8 @@
             SysUiState sysUiState,
             @Main Handler handler,
             PackageManager packageManager,
-            StatusBar statusBar) {
+            StatusBar statusBar,
+            KeyguardUpdateMonitor keyguardUpdateMonitor) {
 
         super(context,
                 windowManagerFuncs,
@@ -204,7 +206,8 @@
                 sysUiState,
                 handler,
                 packageManager,
-                statusBar);
+                statusBar,
+                keyguardUpdateMonitor);
 
         mLockPatternUtils = lockPatternUtils;
         mKeyguardStateController = keyguardStateController;
@@ -266,7 +269,7 @@
                 this::getWalletViewController, mSysuiColorExtractor,
                 mStatusBarService, mNotificationShadeWindowController,
                 mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger(),
-                getStatusBar());
+                getStatusBar(), getKeyguardUpdateMonitor(), mLockPatternUtils);
 
         if (shouldShowLockMessage(dialog)) {
             dialog.showLockMessage();
@@ -334,12 +337,13 @@
                 NotificationShadeWindowController notificationShadeWindowController,
                 SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
                 MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
-                StatusBar statusBar) {
+                StatusBar statusBar, KeyguardUpdateMonitor keyguardUpdateMonitor,
+                LockPatternUtils lockPatternUtils) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
                     adapter, overflowAdapter, sysuiColorExtractor, statusBarService,
                     notificationShadeWindowController, sysuiState, onRotateCallback,
                     keyguardShowing, powerAdapter, uiEventLogger, null,
-                    statusBar);
+                    statusBar, keyguardUpdateMonitor, lockPatternUtils);
             mWalletFactory = walletFactory;
 
             // Update window attributes
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 06e7482..9ada54b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -84,6 +84,7 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
@@ -108,6 +109,7 @@
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.MultiListLayout;
 import com.android.systemui.MultiListLayout.MultiListAdapter;
 import com.android.systemui.animation.Interpolators;
@@ -170,6 +172,11 @@
     static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
     static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
 
+    // See NotificationManagerService#scheduleDurationReachedLocked
+    private static final long TOAST_FADE_TIME = 333;
+    // See NotificationManagerService.LONG_DELAY
+    private static final int TOAST_VISIBLE_TIME = 3500;
+
     private final Context mContext;
     private final GlobalActionsManager mWindowManagerFuncs;
     private final AudioManager mAudioManager;
@@ -231,6 +238,7 @@
     protected Handler mMainHandler;
     private int mSmallestScreenWidthDp;
     private final StatusBar mStatusBar;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     @VisibleForTesting
     public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
@@ -338,7 +346,8 @@
             SysUiState sysUiState,
             @Main Handler handler,
             PackageManager packageManager,
-            StatusBar statusBar) {
+            StatusBar statusBar,
+            KeyguardUpdateMonitor keyguardUpdateMonitor) {
         mContext = context;
         mWindowManagerFuncs = windowManagerFuncs;
         mAudioManager = audioManager;
@@ -369,6 +378,7 @@
         mMainHandler = handler;
         mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
         mStatusBar = statusBar;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -422,6 +432,10 @@
         return mStatusBar;
     }
 
+    protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
+        return mKeyguardUpdateMonitor;
+    }
+
     /**
      * Show the global actions dialog (creating if necessary)
      *
@@ -653,7 +667,7 @@
                 mAdapter, mOverflowAdapter, mSysuiColorExtractor,
                 mStatusBarService, mNotificationShadeWindowController,
                 mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
-                mInfoProvider, mStatusBar);
+                mInfoProvider, mStatusBar, mKeyguardUpdateMonitor, mLockPatternUtils);
 
         dialog.setOnDismissListener(this);
         dialog.setOnShowListener(this);
@@ -2122,6 +2136,8 @@
         private GlobalActionsInfoProvider mInfoProvider;
         private GestureDetector mGestureDetector;
         private StatusBar mStatusBar;
+        private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+        private LockPatternUtils mLockPatternUtils;
 
         protected ViewGroup mContainer;
 
@@ -2173,7 +2189,8 @@
                 NotificationShadeWindowController notificationShadeWindowController,
                 SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
                 MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
-                @Nullable GlobalActionsInfoProvider infoProvider, StatusBar statusBar) {
+                @Nullable GlobalActionsInfoProvider infoProvider, StatusBar statusBar,
+                KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
             super(context, themeRes);
             mContext = context;
             mAdapter = adapter;
@@ -2188,6 +2205,8 @@
             mUiEventLogger = uiEventLogger;
             mInfoProvider = infoProvider;
             mStatusBar = statusBar;
+            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+            mLockPatternUtils = lockPatternUtils;
 
             mGestureDetector = new GestureDetector(mContext, mGestureListener);
 
@@ -2308,6 +2327,14 @@
             if (mInfoProvider != null && mInfoProvider.shouldShowMessage()) {
                 mInfoProvider.addPanel(mContext, mContainer, mAdapter.getCount(), () -> dismiss());
             }
+
+            // If user entered from the lock screen and smart lock was enabled, disable it
+            int user = KeyguardUpdateMonitor.getCurrentUser();
+            boolean userHasTrust = mKeyguardUpdateMonitor.getUserHasTrust(user);
+            if (mKeyguardShowing && userHasTrust) {
+                mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
+                showSmartLockDisabledMessage();
+            }
         }
 
         protected void fixNavBarClipping() {
@@ -2319,6 +2346,37 @@
             contentParent.setClipToPadding(false);
         }
 
+        private void showSmartLockDisabledMessage() {
+            // Since power menu is the top window, make a Toast-like view that will show up
+            View message = LayoutInflater.from(mContext)
+                    .inflate(com.android.systemui.R.layout.global_actions_toast, mContainer, false);
+
+            // Set up animation
+            AccessibilityManager mAccessibilityManager =
+                    (AccessibilityManager) getContext().getSystemService(
+                            Context.ACCESSIBILITY_SERVICE);
+            final int visibleTime = mAccessibilityManager.getRecommendedTimeoutMillis(
+                    TOAST_VISIBLE_TIME, AccessibilityManager.FLAG_CONTENT_TEXT);
+            message.setVisibility(View.VISIBLE);
+            message.setAlpha(0f);
+            mContainer.addView(message);
+
+            // Fade in
+            message.animate()
+                    .alpha(1f)
+                    .setDuration(TOAST_FADE_TIME)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            // Then fade out
+                            message.animate()
+                                    .alpha(0f)
+                                    .setDuration(TOAST_FADE_TIME)
+                                    .setStartDelay(visibleTime);
+                        }
+                    });
+        }
+
         @Override
         protected void onStart() {
             super.onStart();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
deleted file mode 100644
index 38b20ee..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.qs;
-
-import static com.android.systemui.statusbar.phone.AutoTileManager.HOTSPOT;
-import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
-import static com.android.systemui.statusbar.phone.AutoTileManager.NIGHT;
-import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
-import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings.Secure;
-import android.text.TextUtils;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
-import com.android.systemui.util.UserAwareController;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-import javax.inject.Inject;
-
-public class AutoAddTracker implements UserAwareController {
-
-    private static final String[][] CONVERT_PREFS = {
-            {Key.QS_HOTSPOT_ADDED, HOTSPOT},
-            {Key.QS_DATA_SAVER_ADDED, SAVER},
-            {Key.QS_INVERT_COLORS_ADDED, INVERSION},
-            {Key.QS_WORK_ADDED, WORK},
-            {Key.QS_NIGHTDISPLAY_ADDED, NIGHT},
-    };
-
-    private final ArraySet<String> mAutoAdded;
-    private final Context mContext;
-    private int mUserId;
-
-    public AutoAddTracker(Context context, int userId) {
-        mContext = context;
-        mUserId = userId;
-        mAutoAdded = new ArraySet<>(getAdded());
-    }
-
-    /**
-     * Init method must be called after construction to start listening
-     */
-    public void initialize() {
-        // TODO: remove migration code and shared preferences keys after P release
-        if (mUserId == UserHandle.USER_SYSTEM) {
-            for (String[] convertPref : CONVERT_PREFS) {
-                if (Prefs.getBoolean(mContext, convertPref[0], false)) {
-                    setTileAdded(convertPref[1]);
-                    Prefs.remove(mContext, convertPref[0]);
-                }
-            }
-        }
-        mContext.getContentResolver().registerContentObserver(
-                Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver,
-                UserHandle.USER_ALL);
-    }
-
-    @Override
-    public void changeUser(UserHandle newUser) {
-        if (newUser.getIdentifier() == mUserId) {
-            return;
-        }
-        mUserId = newUser.getIdentifier();
-        mAutoAdded.clear();
-        mAutoAdded.addAll(getAdded());
-    }
-
-    @Override
-    public int getCurrentUserId() {
-        return mUserId;
-    }
-
-    public boolean isAdded(String tile) {
-        return mAutoAdded.contains(tile);
-    }
-
-    public void setTileAdded(String tile) {
-        if (mAutoAdded.add(tile)) {
-            saveTiles();
-        }
-    }
-
-    public void setTileRemoved(String tile) {
-        if (mAutoAdded.remove(tile)) {
-            saveTiles();
-        }
-    }
-
-    public void destroy() {
-        mContext.getContentResolver().unregisterContentObserver(mObserver);
-    }
-
-    private void saveTiles() {
-        Secure.putStringForUser(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES,
-                TextUtils.join(",", mAutoAdded), mUserId);
-    }
-
-    private Collection<String> getAdded() {
-        String current = Secure.getStringForUser(mContext.getContentResolver(),
-                Secure.QS_AUTO_ADDED_TILES, mUserId);
-        if (current == null) {
-            return Collections.emptyList();
-        }
-        return Arrays.asList(current.split(","));
-    }
-
-    @VisibleForTesting
-    protected final ContentObserver mObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            mAutoAdded.clear();
-            mAutoAdded.addAll(getAdded());
-        }
-    };
-
-    public static class Builder {
-        private final Context mContext;
-        private int mUserId;
-
-        @Inject
-        public Builder(Context context) {
-            mContext = context;
-        }
-
-        public Builder setUserId(int userId) {
-            mUserId = userId;
-            return this;
-        }
-
-        public AutoAddTracker build() {
-            return new AutoAddTracker(mContext, mUserId);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
new file mode 100644
index 0000000..7ffa9d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.ArraySet
+import android.util.Log
+import androidx.annotation.GuardedBy
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.UserAwareController
+import com.android.systemui.util.settings.SecureSettings
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+private const val TAG = "AutoAddTracker"
+
+/**
+ * Class to track tiles that have been auto-added
+ *
+ * The list is backed by [Settings.Secure.QS_AUTO_ADDED_TILES].
+ *
+ * It also handles restore gracefully.
+ */
+class AutoAddTracker @VisibleForTesting constructor(
+    private val secureSettings: SecureSettings,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val qsHost: QSHost,
+    private val dumpManager: DumpManager,
+    private val mainHandler: Handler?,
+    private val backgroundExecutor: Executor,
+    private var userId: Int
+) : UserAwareController, Dumpable {
+
+    companion object {
+        private val FILTER = IntentFilter(Intent.ACTION_SETTING_RESTORED)
+    }
+
+    @GuardedBy("autoAdded")
+    private val autoAdded = ArraySet<String>()
+    private var restoredTiles: Set<String>? = null
+
+    override val currentUserId: Int
+        get() = userId
+
+    private val contentObserver = object : ContentObserver(mainHandler) {
+        override fun onChange(
+            selfChange: Boolean,
+            uris: Collection<Uri>,
+            flags: Int,
+            _userId: Int
+        ) {
+            if (_userId != userId) {
+                // Ignore changes outside of our user. We'll load the correct value on user change
+                return
+            }
+            loadTiles()
+        }
+    }
+
+    private val restoreReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            if (intent.action != Intent.ACTION_SETTING_RESTORED) return
+            processRestoreIntent(intent)
+        }
+    }
+
+    private fun processRestoreIntent(intent: Intent) {
+        when (intent.getStringExtra(Intent.EXTRA_SETTING_NAME)) {
+            Settings.Secure.QS_TILES -> {
+                restoredTiles = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)
+                        ?.split(",")
+                        ?.toSet()
+                        ?: run {
+                            Log.w(TAG, "Null restored tiles for user $userId")
+                            emptySet()
+                        }
+            }
+            Settings.Secure.QS_AUTO_ADDED_TILES -> {
+                restoredTiles?.let { tiles ->
+                    val restoredAutoAdded = intent
+                            .getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)
+                            ?.split(",")
+                            ?: emptyList()
+                    val autoAddedBeforeRestore = intent
+                            .getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE)
+                            ?.split(",")
+                            ?: emptyList()
+
+                    val tilesToRemove = restoredAutoAdded.filter { it !in tiles }
+                    if (tilesToRemove.isNotEmpty()) {
+                        qsHost.removeTiles(tilesToRemove)
+                    }
+                    val tiles = synchronized(autoAdded) {
+                        autoAdded.clear()
+                        autoAdded.addAll(restoredAutoAdded + autoAddedBeforeRestore)
+                        getTilesFromListLocked()
+                    }
+                    saveTiles(tiles)
+                } ?: run {
+                    Log.w(TAG, "${Settings.Secure.QS_AUTO_ADDED_TILES} restored before " +
+                            "${Settings.Secure.QS_TILES} for user $userId")
+                }
+            }
+            else -> {} // Do nothing for other Settings
+        }
+    }
+
+    /**
+     * Init method must be called after construction to start listening
+     */
+    fun initialize() {
+        dumpManager.registerDumpable(TAG, this)
+        loadTiles()
+        secureSettings.registerContentObserverForUser(
+                secureSettings.getUriFor(Settings.Secure.QS_AUTO_ADDED_TILES),
+                contentObserver,
+                UserHandle.USER_ALL
+        )
+        registerBroadcastReceiver()
+    }
+
+    /**
+     * Unregister listeners, receivers and observers
+     */
+    fun destroy() {
+        dumpManager.unregisterDumpable(TAG)
+        secureSettings.unregisterContentObserver(contentObserver)
+        unregisterBroadcastReceiver()
+    }
+
+    private fun registerBroadcastReceiver() {
+        broadcastDispatcher.registerReceiver(
+                restoreReceiver,
+                FILTER,
+                backgroundExecutor,
+                UserHandle.of(userId)
+        )
+    }
+
+    private fun unregisterBroadcastReceiver() {
+        broadcastDispatcher.unregisterReceiver(restoreReceiver)
+    }
+
+    override fun changeUser(newUser: UserHandle) {
+        if (newUser.identifier == userId) return
+        unregisterBroadcastReceiver()
+        userId = newUser.identifier
+        restoredTiles = null
+        loadTiles()
+        registerBroadcastReceiver()
+    }
+
+    /**
+     * Returns `true` if the tile has been auto-added before
+     */
+    fun isAdded(tile: String): Boolean {
+        return synchronized(autoAdded) {
+            tile in autoAdded
+        }
+    }
+
+    /**
+     * Sets a tile as auto-added.
+     *
+     * From here on, [isAdded] will return true for that tile.
+     */
+    fun setTileAdded(tile: String) {
+        val tiles = synchronized(autoAdded) {
+                if (autoAdded.add(tile)) {
+                    getTilesFromListLocked()
+                } else {
+                    null
+                }
+            }
+        tiles?.let { saveTiles(it) }
+    }
+
+    /**
+     * Removes a tile from the list of auto-added.
+     *
+     * This allows for this tile to be auto-added again in the future.
+     */
+    fun setTileRemoved(tile: String) {
+        val tiles = synchronized(autoAdded) {
+            if (autoAdded.remove(tile)) {
+                getTilesFromListLocked()
+            } else {
+                null
+            }
+        }
+        tiles?.let { saveTiles(it) }
+    }
+
+    private fun getTilesFromListLocked(): String {
+        return TextUtils.join(",", autoAdded)
+    }
+
+    private fun saveTiles(tiles: String) {
+        secureSettings.putStringForUser(
+                Settings.Secure.QS_AUTO_ADDED_TILES,
+                tiles,
+                /* tag */ null,
+                /* makeDefault */ false,
+                userId,
+                /* overrideableByRestore */ true
+        )
+    }
+
+    private fun loadTiles() {
+        synchronized(autoAdded) {
+            autoAdded.clear()
+            autoAdded.addAll(getAdded())
+        }
+    }
+
+    private fun getAdded(): Collection<String> {
+        val current = secureSettings.getStringForUser(Settings.Secure.QS_AUTO_ADDED_TILES, userId)
+        return current?.split(",") ?: emptySet()
+    }
+
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("Current user: $userId")
+        pw.println("Added tiles: $autoAdded")
+    }
+
+    @SysUISingleton
+    class Builder @Inject constructor(
+        private val secureSettings: SecureSettings,
+        private val broadcastDispatcher: BroadcastDispatcher,
+        private val qsHost: QSHost,
+        private val dumpManager: DumpManager,
+        @Main private val handler: Handler,
+        @Background private val executor: Executor
+    ) {
+        private var userId: Int = 0
+
+        fun setUserId(_userId: Int): Builder {
+            userId = _userId
+            return this
+        }
+
+        fun build(): AutoAddTracker {
+            return AutoAddTracker(
+                    secureSettings,
+                    broadcastDispatcher,
+                    qsHost,
+                    dumpManager,
+                    handler,
+                    executor,
+                    userId
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 000fd1c..9f585bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -37,6 +37,7 @@
     void removeCallback(Callback callback);
     TileServices getTileServices();
     void removeTile(String tileSpec);
+    void removeTiles(Collection<String> specs);
     void unmarkTileAsAutoAdded(String tileSpec);
 
     int indexOf(String tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 541ee2c..d5349d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -347,6 +347,17 @@
         changeTileSpecs(tileSpecs-> tileSpecs.remove(spec));
     }
 
+    /**
+     * Remove many tiles at once.
+     *
+     * It will only save to settings once (as opposed to {@link QSTileHost#removeTile} called
+     * multiple times).
+     */
+    @Override
+    public void removeTiles(Collection<String> specs) {
+        changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs));
+    }
+
     @Override
     public void unmarkTileAsAutoAdded(String spec) {
         if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
@@ -368,6 +379,7 @@
      * @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
      */
     public void addTile(String spec, int requestPosition) {
+        if (spec.equals("work")) Log.wtfStack(TAG, "Adding work tile");
         changeTileSpecs(tileSpecs -> {
             if (tileSpecs.contains(spec)) return false;
 
@@ -382,6 +394,7 @@
     }
 
     void saveTilesToSettings(List<String> tileSpecs) {
+        if (tileSpecs.contains("work")) Log.wtfStack(TAG, "Saving work tile");
         mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
                 null /* tag */, false /* default */, mCurrentUser,
                 true /* overrideable by restore */);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 77906ab..19d5fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.VariableDateView;
 
 import java.util.List;
 
@@ -62,11 +63,14 @@
     protected QuickQSPanel mHeaderQsPanel;
     private View mDatePrivacyView;
     private View mDateView;
+    // DateView next to clock. Visible on QQS
+    private VariableDateView mClockDateView;
     private View mSecurityHeaderView;
     private View mClockIconsView;
     private View mContainer;
 
     private View mQSCarriers;
+    private ViewGroup mClockContainer;
     private Clock mClockView;
     private Space mDatePrivacySeparator;
     private View mClockIconsSeparator;
@@ -86,7 +90,6 @@
     private int mWaterfallTopInset;
     private int mCutOutPaddingLeft;
     private int mCutOutPaddingRight;
-    private float mViewAlpha = 1.0f;
     private float mKeyguardExpansionFraction;
     private int mTextColorPrimary = Color.TRANSPARENT;
     private int mTopViewMeasureHeight;
@@ -123,12 +126,14 @@
         mIconContainer = findViewById(R.id.statusIcons);
         mPrivacyChip = findViewById(R.id.privacy_chip);
         mDateView = findViewById(R.id.date);
+        mClockDateView = findViewById(R.id.date_clock);
         mSecurityHeaderView = findViewById(R.id.header_text_container);
         mClockIconsSeparator = findViewById(R.id.separator);
         mRightLayout = findViewById(R.id.rightLayout);
         mDateContainer = findViewById(R.id.date_container);
         mPrivacyContainer = findViewById(R.id.privacy_container);
 
+        mClockContainer = findViewById(R.id.clock_container);
         mClockView = findViewById(R.id.clock);
         mDatePrivacySeparator = findViewById(R.id.space);
         // Tint for the battery icons are handled in setupHost()
@@ -177,7 +182,7 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mDatePrivacyView.getMeasuredHeight() != mTopViewMeasureHeight) {
             mTopViewMeasureHeight = mDatePrivacyView.getMeasuredHeight();
-            updateAnimators();
+            post(this::updateAnimators);
         }
     }
 
@@ -280,7 +285,8 @@
         TouchAnimator.Builder builder = new TouchAnimator.Builder()
                 .addFloat(mSecurityHeaderView, "alpha", 0, 1)
                 // These views appear on expanding down
-                .addFloat(mClockView, "alpha", 0, 1)
+                .addFloat(mDateView, "alpha", 0, 0, 1)
+                .addFloat(mClockDateView, "alpha", 1, 0, 0)
                 .addFloat(mQSCarriers, "alpha", 0, 1)
                 .setListener(new TouchAnimator.ListenerAdapter() {
                     @Override
@@ -289,10 +295,14 @@
                         if (!mIsSingleCarrier) {
                             mIconContainer.addIgnoredSlots(mRssiIgnoredSlots);
                         }
+                        // Make it gone so there's enough room for carrier names
+                        mClockDateView.setVisibility(View.GONE);
                     }
 
                     @Override
                     public void onAnimationStarted() {
+                        mClockDateView.setVisibility(View.VISIBLE);
+                        mClockDateView.setFreezeSwitching(true);
                         setSeparatorVisibility(false);
                         if (!mIsSingleCarrier) {
                             mIconContainer.addIgnoredSlots(mRssiIgnoredSlots);
@@ -302,6 +312,7 @@
                     @Override
                     public void onAnimationAtStart() {
                         super.onAnimationAtStart();
+                        mClockDateView.setFreezeSwitching(false);
                         setSeparatorVisibility(mShowClockIconsSeparator);
                         // In QQS we never ignore RSSI.
                         mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots);
@@ -434,10 +445,11 @@
         mClockIconsSeparator.setVisibility(visible ? View.VISIBLE : View.GONE);
         mQSCarriers.setVisibility(visible ? View.GONE : View.VISIBLE);
 
-        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mClockView.getLayoutParams();
+        LinearLayout.LayoutParams lp =
+                (LinearLayout.LayoutParams) mClockContainer.getLayoutParams();
         lp.width = visible ? 0 : WRAP_CONTENT;
         lp.weight = visible ? 1f : 0f;
-        mClockView.setLayoutParams(lp);
+        mClockContainer.setLayoutParams(lp);
 
         lp = (LinearLayout.LayoutParams) mRightLayout.getLayoutParams();
         lp.width = visible ? 0 : WRAP_CONTENT;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index da75c9e..18d6e64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -41,6 +41,7 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.VariableDateViewController;
 import com.android.systemui.util.ViewController;
 
 import java.util.List;
@@ -71,6 +72,9 @@
     private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
     private final FeatureFlags mFeatureFlags;
 
+    private final VariableDateViewController mVariableDateViewControllerDateView;
+    private final VariableDateViewController mVariableDateViewControllerClockDateView;
+
     private boolean mListening;
     private boolean mMicCameraIndicatorsEnabled;
     private boolean mLocationIndicatorsEnabled;
@@ -134,7 +138,8 @@
             SysuiColorExtractor colorExtractor,
             PrivacyDialogController privacyDialogController,
             QSExpansionPathInterpolator qsExpansionPathInterpolator,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            VariableDateViewController.Factory variableDateViewControllerFactory) {
         super(view);
         mPrivacyItemController = privacyItemController;
         mActivityStarter = activityStarter;
@@ -154,6 +159,12 @@
         mPrivacyChip = mView.findViewById(R.id.privacy_chip);
         mClockView = mView.findViewById(R.id.clock);
         mIconContainer = mView.findViewById(R.id.statusIcons);
+        mVariableDateViewControllerDateView = variableDateViewControllerFactory.create(
+                mView.requireViewById(R.id.date)
+        );
+        mVariableDateViewControllerClockDateView = variableDateViewControllerFactory.create(
+                mView.requireViewById(R.id.date_clock)
+        );
 
         mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags);
         mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
@@ -205,6 +216,9 @@
         mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots);
 
         mDemoModeController.addCallback(mDemoModeReceiver);
+
+        mVariableDateViewControllerDateView.init();
+        mVariableDateViewControllerClockDateView.init();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 4b13015..04f089d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -150,11 +150,7 @@
         }
 
         List<CastDevice> activeDevices = getActiveDevices();
-        // We want to pop up the media route selection dialog if we either have no active devices
-        // (neither routes nor projection), or if we have an active route. In other cases, we assume
-        // that a projection is active. This is messy, but this tile never correctly handled the
-        // case where multiple devices were active :-/.
-        if (activeDevices.isEmpty() || (activeDevices.get(0).tag instanceof RouteInfo)) {
+        if (willPopDetail()) {
             mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                 showDetail(true);
             });
@@ -163,6 +159,15 @@
         }
     }
 
+    // We want to pop up the media route selection dialog if we either have no active devices
+    // (neither routes nor projection), or if we have an active route. In other cases, we assume
+    // that a projection is active. This is messy, but this tile never correctly handled the
+    // case where multiple devices were active :-/.
+    private boolean willPopDetail() {
+        List<CastDevice> activeDevices = getActiveDevices();
+        return activeDevices.isEmpty() || (activeDevices.get(0).tag instanceof RouteInfo);
+    }
+
     private List<CastDevice> getActiveDevices() {
         ArrayList<CastDevice> activeDevices = new ArrayList<>();
         for (CastDevice device : mController.getCastDevices()) {
@@ -234,10 +239,12 @@
             state.contentDescription = state.contentDescription + ","
                     + mContext.getString(R.string.accessibility_quick_settings_open_details);
             state.expandedAccessibilityClassName = Button.class.getName();
+            state.forceExpandIcon = willPopDetail();
         } else {
             state.state = Tile.STATE_UNAVAILABLE;
             String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
             state.secondaryLabel = noWifi;
+            state.forceExpandIcon = false;
         }
         state.stateDescription = state.stateDescription + ", " + state.secondaryLabel;
         mDetailAdapter.updateItems(devices);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 7cb1421..cc9e748 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -51,7 +51,9 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
 import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -66,15 +68,16 @@
 /** Quick settings tile: Internet **/
 public class InternetTile extends QSTileImpl<SignalState> {
     private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
-    private static final Intent INTERNET_PANEL =
-            new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
 
     protected final NetworkController mController;
+    private final AccessPointController mAccessPointController;
     private final DataUsageController mDataController;
     // The last updated tile state, 0: mobile, 1: wifi, 2: ethernet.
     private int mLastTileState = -1;
 
     protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback();
+    private final InternetDialogFactory mInternetDialogFactory;
+    final Handler mHandler;
 
     @Inject
     public InternetTile(
@@ -86,11 +89,16 @@
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
-            NetworkController networkController
+            NetworkController networkController,
+            AccessPointController accessPointController,
+            InternetDialogFactory internetDialogFactory
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
+        mInternetDialogFactory = internetDialogFactory;
+        mHandler = mainHandler;
         mController = networkController;
+        mAccessPointController = accessPointController;
         mDataController = mController.getMobileDataController();
         mController.observe(getLifecycle(), mSignalCallback);
     }
@@ -114,7 +122,9 @@
 
     @Override
     protected void handleClick(@Nullable View view) {
-        mActivityStarter.postStartActivityDismissingKeyguard(INTERNET_PANEL, 0);
+        mHandler.post(() -> mInternetDialogFactory.create(true,
+                mAccessPointController.canConfigMobileData(),
+                mAccessPointController.canConfigWifi()));
     }
 
     @Override
@@ -429,7 +439,7 @@
                 state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
             }
         } else if (cb.mNoDefaultNetwork) {
-            if (cb.mNoNetworksAvailable) {
+            if (cb.mNoNetworksAvailable || !cb.mEnabled) {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
                 state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
             } else {
@@ -489,7 +499,7 @@
             state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
             state.secondaryLabel = r.getString(R.string.status_bar_airplane);
         } else if (cb.mNoDefaultNetwork) {
-            if (cb.mNoNetworksAvailable) {
+            if (cb.mNoNetworksAvailable || !mSignalCallback.mWifiInfo.mEnabled) {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
                 state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
new file mode 100644
index 0000000..4e897d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.dialog;
+
+import static com.android.wifitrackerlib.WifiEntry.SECURITY_NONE;
+import static com.android.wifitrackerlib.WifiEntry.SECURITY_OWE;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.text.Html;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.settingslib.Utils;
+import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.R;
+import com.android.wifitrackerlib.WifiEntry;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Adapter for showing Wi-Fi networks.
+ */
+public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> {
+
+    private static final String TAG = "InternetAdapter";
+    private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
+    private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
+    private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
+
+    private final InternetDialogController mInternetDialogController;
+    private List<WifiEntry> mWifiEntries;
+    private int mWifiEntriesCount;
+
+    protected View mHolderView;
+    protected Context mContext;
+
+    public InternetAdapter(InternetDialogController controller) {
+        mInternetDialogController = controller;
+    }
+
+    @Override
+    public InternetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
+            int viewType) {
+        mContext = viewGroup.getContext();
+        mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item,
+                viewGroup, false);
+        return new InternetViewHolder(mHolderView, mInternetDialogController);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) {
+        if (mWifiEntries == null || position >= mWifiEntriesCount) {
+            return;
+        }
+        viewHolder.onBind(mWifiEntries.get(position));
+    }
+
+    /**
+     * Updates the Wi-Fi networks.
+     *
+     * @param wifiEntries the updated Wi-Fi entries.
+     * @param wifiEntriesCount the total number of Wi-Fi entries.
+     */
+    public void setWifiEntries(@Nullable List<WifiEntry> wifiEntries, int wifiEntriesCount) {
+        mWifiEntries = wifiEntries;
+        mWifiEntriesCount = wifiEntriesCount;
+    }
+
+    /**
+     * Gets the total number of Wi-Fi networks.
+     *
+     * @return The total number of Wi-Fi entries.
+     */
+    @Override
+    public int getItemCount() {
+        return mWifiEntriesCount;
+    }
+
+    /**
+     * ViewHolder for binding Wi-Fi view.
+     */
+    static class InternetViewHolder extends RecyclerView.ViewHolder {
+
+        final LinearLayout mContainerLayout;
+        final LinearLayout mWifiListLayout;
+        final LinearLayout mWifiNetworkLayout;
+        final ImageView mWifiIcon;
+        final TextView mWifiTitleText;
+        final TextView mWifiSummaryText;
+        final ImageView mWifiLockedIcon;
+        final Context mContext;
+        final InternetDialogController mInternetDialogController;
+
+        protected WifiUtils.InternetIconInjector mWifiIconInjector;
+
+        InternetViewHolder(View view, InternetDialogController internetDialogController) {
+            super(view);
+            mContext = view.getContext();
+            mInternetDialogController = internetDialogController;
+            mContainerLayout = view.requireViewById(R.id.internet_container);
+            mWifiListLayout = view.requireViewById(R.id.wifi_list);
+            mWifiNetworkLayout = view.requireViewById(R.id.wifi_network_layout);
+            mWifiIcon = view.requireViewById(R.id.wifi_icon);
+            mWifiTitleText = view.requireViewById(R.id.wifi_title);
+            mWifiSummaryText = view.requireViewById(R.id.wifi_summary);
+            mWifiLockedIcon = view.requireViewById(R.id.wifi_locked_icon);
+            mWifiIconInjector = mInternetDialogController.getWifiIconInjector();
+        }
+
+        void onBind(WifiEntry wifiEntry) {
+            int security = wifiEntry.getSecurity();
+            try {
+                mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
+                if (isOpenNetwork(security)) {
+                    mWifiLockedIcon.setVisibility(View.GONE);
+                } else {
+                    mWifiLockedIcon.setVisibility(View.VISIBLE);
+                    mWifiLockedIcon.setImageDrawable(
+                            mContext.getDrawable(R.drawable.ic_friction_lock_closed));
+                }
+            } catch (Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            setWifiNetworkLayout(wifiEntry.getTitle(),
+                    Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY));
+
+            mWifiListLayout.setOnClickListener(v -> {
+                if (wifiEntry.shouldEditBeforeConnect()) {
+                    final Intent intent = new Intent(ACTION_WIFI_DIALOG);
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+                    intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, wifiEntry.getKey());
+                    intent.putExtra(EXTRA_CONNECT_FOR_CALLER, false);
+                    mContext.startActivity(intent);
+                }
+                mInternetDialogController.connect(wifiEntry);
+            });
+        }
+
+        /** Return true if this is an open network AccessPoint. */
+        boolean isOpenNetwork(int security) {
+            return security == SECURITY_NONE
+                    || security == SECURITY_OWE;
+        }
+
+        void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
+            mWifiNetworkLayout.setVisibility(View.VISIBLE);
+            mWifiTitleText.setText(title);
+            if (TextUtils.isEmpty(summary)) {
+                mWifiSummaryText.setVisibility(View.GONE);
+                return;
+            } else {
+                mWifiSummaryText.setVisibility(View.VISIBLE);
+            }
+            mWifiSummaryText.setText(summary);
+        }
+
+        Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) throws Throwable {
+            if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
+                return null;
+            }
+            final Drawable drawable = mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(),
+                    wifiEntry.getLevel());
+            if (drawable == null) {
+                return null;
+            }
+            drawable.setTint(
+                    Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorTertiary));
+            final AtomicReference<Drawable> shared = new AtomicReference<>();
+            shared.set(drawable);
+            return shared.get();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
new file mode 100644
index 0000000..4d0cbd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.tiles.dialog;
+
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+
+import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyDisplayInfo;
+import android.telephony.TelephonyManager;
+import android.text.Html;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.Utils;
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.wifitrackerlib.WifiEntry;
+
+import java.util.List;
+
+/**
+ * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
+ */
+@SysUISingleton
+public class InternetDialog extends SystemUIDialog implements
+        InternetDialogController.InternetDialogCallback, Window.Callback {
+    private static final String TAG = "InternetDialog";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    static final long PROGRESS_DELAY_MS = 2000L;
+
+    private final Handler mHandler;
+    private final LinearLayoutManager mLayoutManager;
+
+    @VisibleForTesting
+    protected InternetAdapter mAdapter;
+    @VisibleForTesting
+    protected WifiManager mWifiManager;
+    @VisibleForTesting
+    protected View mDialogView;
+    @VisibleForTesting
+    protected boolean mCanConfigWifi;
+
+    private InternetDialogFactory mInternetDialogFactory;
+    private SubscriptionManager mSubscriptionManager;
+    private TelephonyManager mTelephonyManager;
+    private AlertDialog mAlertDialog;
+    private UiEventLogger mUiEventLogger;
+    private Context mContext;
+    private InternetDialogController mInternetDialogController;
+    private TextView mInternetDialogTitle;
+    private TextView mInternetDialogSubTitle;
+    private View mDivider;
+    private ProgressBar mProgressBar;
+    private LinearLayout mInternetDialogLayout;
+    private LinearLayout mInternetListLayout;
+    private LinearLayout mConnectedWifListLayout;
+    private LinearLayout mConnectedWifList;
+    private LinearLayout mMobileNetworkLayout;
+    private LinearLayout mMobileNetworkList;
+    private LinearLayout mTurnWifiOnLayout;
+    private TextView mWifiToggleTitleText;
+    private LinearLayout mSeeAllLayout;
+    private RecyclerView mWifiRecyclerView;
+    private ImageView mConnectedWifiIcon;
+    private ImageView mWifiSettingsIcon;
+    private TextView mConnectedWifiTitleText;
+    private TextView mConnectedWifiSummaryText;
+    private ImageView mSignalIcon;
+    private TextView mMobileTitleText;
+    private TextView mMobileSummaryText;
+    private Switch mMobileDataToggle;
+    private Switch mWiFiToggle;
+    private Button mDoneButton;
+    private Drawable mBackgroundOn;
+    private int mListMaxHeight;
+    private int mLayoutWidth;
+    private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    private boolean mCanConfigMobileData;
+
+    // Wi-Fi entries
+    protected WifiEntry mConnectedWifiEntry;
+    protected int mWifiEntriesCount;
+
+    // Wi-Fi scanning progress bar
+    protected boolean mIsProgressBarVisible;
+    protected boolean mIsSearchingHidden;
+    protected final Runnable mHideProgressBarRunnable = () -> {
+        setProgressBarVisible(false);
+    };
+    protected Runnable mHideSearchingRunnable = () -> {
+        mIsSearchingHidden = true;
+        mInternetDialogSubTitle.setText(getSubtitleText());
+    };
+
+    private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
+        // Set max height for list
+        if (mInternetDialogLayout.getHeight() > mListMaxHeight) {
+            ViewGroup.LayoutParams params = mInternetDialogLayout.getLayoutParams();
+            params.height = mListMaxHeight;
+            mInternetDialogLayout.setLayoutParams(params);
+        }
+    };
+
+    public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
+            InternetDialogController internetDialogController, boolean canConfigMobileData,
+            boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
+            @Main Handler handler) {
+        super(context, R.style.Theme_SystemUI_Dialog_Internet);
+        if (DEBUG) {
+            Log.d(TAG, "Init InternetDialog");
+        }
+        mContext = context;
+        mHandler = handler;
+        mInternetDialogFactory = internetDialogFactory;
+        mInternetDialogController = internetDialogController;
+        mSubscriptionManager = mInternetDialogController.getSubscriptionManager();
+        mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
+        mTelephonyManager = mInternetDialogController.getTelephonyManager();
+        mWifiManager = mInternetDialogController.getWifiManager();
+        mCanConfigMobileData = canConfigMobileData;
+        mCanConfigWifi = canConfigWifi;
+
+        mLayoutManager = new LinearLayoutManager(mContext) {
+            @Override
+            public boolean canScrollVertically() {
+                return false;
+            }
+        };
+        mListMaxHeight = context.getResources().getDimensionPixelSize(
+                R.dimen.internet_dialog_list_max_height);
+        mLayoutWidth = context.getResources().getDimensionPixelSize(
+                R.dimen.internet_dialog_list_max_width);
+        mUiEventLogger = uiEventLogger;
+        mAdapter = new InternetAdapter(mInternetDialogController);
+        if (!aboveStatusBar) {
+            getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (DEBUG) {
+            Log.d(TAG, "onCreate");
+        }
+        mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW);
+        mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog,
+                null);
+        final Window window = getWindow();
+        final WindowManager.LayoutParams layoutParams = window.getAttributes();
+        layoutParams.gravity = Gravity.BOTTOM;
+        // Move down the dialog to overlay the navigation bar.
+        layoutParams.setFitInsetsTypes(
+                layoutParams.getFitInsetsTypes() & ~WindowInsets.Type.navigationBars());
+        layoutParams.setFitInsetsSides(WindowInsets.Side.all());
+        layoutParams.setFitInsetsIgnoringVisibility(true);
+        window.setAttributes(layoutParams);
+        window.setContentView(mDialogView);
+        //Only fix the width for large screen or tablet.
+        window.setLayout(mContext.getResources().getDimensionPixelSize(
+                R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT);
+        window.setWindowAnimations(R.style.Animation_InternetDialog);
+        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        window.addFlags(FLAG_LAYOUT_NO_LIMITS);
+
+        mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog);
+        mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
+        mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+        mDivider = mDialogView.requireViewById(R.id.divider);
+        mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress);
+        mInternetListLayout = mDialogView.requireViewById(R.id.internet_list);
+        mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
+        mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list);
+        mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+        mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
+        mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
+        mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list);
+        mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
+        mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title);
+        mConnectedWifiSummaryText = mDialogView.requireViewById(R.id.wifi_connected_summary);
+        mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
+        mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
+        mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
+        mDoneButton = mDialogView.requireViewById(R.id.done);
+        mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
+        mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
+        mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
+        mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
+        mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
+        mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
+        mInternetDialogLayout.getViewTreeObserver().addOnGlobalLayoutListener(
+                mInternetListLayoutListener);
+        mInternetDialogTitle.setText(getDialogTitleText());
+        mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
+
+        setOnClickListener();
+        mTurnWifiOnLayout.setBackground(null);
+        mWifiRecyclerView.setLayoutManager(mLayoutManager);
+        mWifiRecyclerView.setAdapter(mAdapter);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (DEBUG) {
+            Log.d(TAG, "onStart");
+        }
+        mInternetDialogController.onStart(this, mCanConfigWifi);
+        if (!mCanConfigWifi) {
+            hideWifiViews();
+        }
+    }
+
+    @VisibleForTesting
+    void hideWifiViews() {
+        setProgressBarVisible(false);
+        mTurnWifiOnLayout.setVisibility(View.GONE);
+        mConnectedWifListLayout.setVisibility(View.GONE);
+        mWifiRecyclerView.setVisibility(View.GONE);
+        mSeeAllLayout.setVisibility(View.GONE);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        if (DEBUG) {
+            Log.d(TAG, "onStop");
+        }
+        mHandler.removeCallbacks(mHideProgressBarRunnable);
+        mHandler.removeCallbacks(mHideSearchingRunnable);
+        mMobileNetworkLayout.setOnClickListener(null);
+        mMobileDataToggle.setOnCheckedChangeListener(null);
+        mConnectedWifListLayout.setOnClickListener(null);
+        mSeeAllLayout.setOnClickListener(null);
+        mWiFiToggle.setOnCheckedChangeListener(null);
+        mDoneButton.setOnClickListener(null);
+        mInternetDialogController.onStop();
+        mInternetDialogFactory.destroyDialog();
+    }
+
+    @Override
+    public void dismissDialog() {
+        if (DEBUG) {
+            Log.d(TAG, "dismissDialog");
+        }
+        mInternetDialogFactory.destroyDialog();
+        dismiss();
+    }
+
+    void updateDialog() {
+        if (DEBUG) {
+            Log.d(TAG, "updateDialog");
+        }
+        if (mInternetDialogController.isAirplaneModeEnabled()) {
+            mInternetDialogSubTitle.setVisibility(View.GONE);
+        } else {
+            mInternetDialogSubTitle.setText(getSubtitleText());
+        }
+        setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular());
+
+        if (!mCanConfigWifi) {
+            return;
+        }
+
+        showProgressBar();
+        final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
+        final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
+        updateWifiToggle(isWifiEnabled, isDeviceLocked);
+        updateConnectedWifi(isWifiEnabled, isDeviceLocked);
+
+        final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0)
+                ? View.GONE : View.VISIBLE;
+        mWifiRecyclerView.setVisibility(visibility);
+        mSeeAllLayout.setVisibility(visibility);
+    }
+
+    private void setOnClickListener() {
+        mMobileNetworkLayout.setOnClickListener(v -> {
+            if (mInternetDialogController.isMobileDataEnabled()
+                    && !mInternetDialogController.isDeviceLocked()) {
+                if (!mInternetDialogController.activeNetworkIsCellular()) {
+                    mInternetDialogController.connectCarrierNetwork();
+                }
+            }
+        });
+        mMobileDataToggle.setOnCheckedChangeListener(
+                (buttonView, isChecked) -> {
+                    if (!isChecked && shouldShowMobileDialog()) {
+                        showTurnOffMobileDialog();
+                    } else if (!shouldShowMobileDialog()) {
+                        mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId,
+                                isChecked, false);
+                    }
+                });
+        mConnectedWifListLayout.setOnClickListener(v -> onClickConnectedWifi());
+        mSeeAllLayout.setOnClickListener(v -> onClickSeeMoreButton());
+        mWiFiToggle.setOnCheckedChangeListener(
+                (buttonView, isChecked) -> {
+                    buttonView.setChecked(isChecked);
+                    mWifiManager.setWifiEnabled(isChecked);
+                });
+        mDoneButton.setOnClickListener(v -> dismiss());
+    }
+
+    private void setMobileDataLayout(boolean isCellularNetwork) {
+        if (mInternetDialogController.isAirplaneModeEnabled()
+                || !mInternetDialogController.hasCarrier()) {
+            mMobileNetworkLayout.setVisibility(View.GONE);
+        } else {
+            mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
+            mMobileNetworkLayout.setVisibility(View.VISIBLE);
+            mMobileTitleText.setText(getMobileNetworkTitle());
+            if (!TextUtils.isEmpty(getMobileNetworkSummary())) {
+                mMobileSummaryText.setText(
+                        Html.fromHtml(getMobileNetworkSummary(), Html.FROM_HTML_MODE_LEGACY));
+                mMobileSummaryText.setVisibility(View.VISIBLE);
+            } else {
+                mMobileSummaryText.setVisibility(View.GONE);
+            }
+            mSignalIcon.setImageDrawable(getSignalStrengthDrawable());
+            if (mInternetDialogController.isNightMode()) {
+                int titleColor = isCellularNetwork ? mContext.getColor(
+                        R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+                        mContext, android.R.attr.textColorPrimary);
+                int summaryColor = isCellularNetwork ? mContext.getColor(
+                        R.color.connected_network_secondary_color) : Utils.getColorAttrDefaultColor(
+                        mContext, android.R.attr.textColorSecondary);
+
+                mMobileTitleText.setTextColor(titleColor);
+                mMobileSummaryText.setTextColor(summaryColor);
+            }
+            mMobileNetworkLayout.setBackground(isCellularNetwork ? mBackgroundOn : null);
+
+            mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
+        mWiFiToggle.setChecked(isWifiEnabled);
+        if (isDeviceLocked && mInternetDialogController.isNightMode()) {
+            int titleColor = mConnectedWifiEntry != null ? mContext.getColor(
+                    R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+                    mContext, android.R.attr.textColorPrimary);
+            mWifiToggleTitleText.setTextColor(titleColor);
+        }
+        mTurnWifiOnLayout.setBackground(
+                (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
+    }
+
+    private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
+        if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
+            mConnectedWifListLayout.setBackground(null);
+            mConnectedWifListLayout.setVisibility(View.GONE);
+            return;
+        }
+        mConnectedWifListLayout.setVisibility(View.VISIBLE);
+        mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
+        mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
+        mConnectedWifiIcon.setImageDrawable(
+                mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
+        if (mInternetDialogController.isNightMode()) {
+            mConnectedWifiTitleText.setTextColor(
+                    mContext.getColor(R.color.connected_network_primary_color));
+            mConnectedWifiSummaryText.setTextColor(
+                    mContext.getColor(R.color.connected_network_secondary_color));
+        }
+        mWifiSettingsIcon.setColorFilter(
+                mContext.getColor(R.color.connected_network_primary_color));
+        mConnectedWifListLayout.setBackground(mBackgroundOn);
+    }
+
+    void onClickConnectedWifi() {
+        mInternetDialogController.launchWifiNetworkDetailsSetting();
+    }
+
+    void onClickSeeMoreButton() {
+        mInternetDialogController.launchNetworkSetting();
+    }
+
+    CharSequence getDialogTitleText() {
+        return mInternetDialogController.getDialogTitleText();
+    }
+
+    CharSequence getSubtitleText() {
+        return mInternetDialogController.getSubtitleText(
+                mIsProgressBarVisible && !mIsSearchingHidden);
+    }
+
+    private Drawable getSignalStrengthDrawable() {
+        return mInternetDialogController.getSignalStrengthDrawable();
+    }
+
+    CharSequence getMobileNetworkTitle() {
+        return mInternetDialogController.getMobileNetworkTitle();
+    }
+
+    String getMobileNetworkSummary() {
+        return mInternetDialogController.getMobileNetworkSummary();
+    }
+
+    protected void showProgressBar() {
+        if (mWifiManager == null || !mWifiManager.isWifiEnabled()
+                || mInternetDialogController.isDeviceLocked()) {
+            setProgressBarVisible(false);
+            return;
+        }
+        setProgressBarVisible(true);
+        if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) {
+            mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
+        } else if (!mIsSearchingHidden) {
+            mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
+        }
+    }
+
+    private void setProgressBarVisible(boolean visible) {
+        if (mWifiManager.isWifiEnabled() && mAdapter.mHolderView != null
+                && mAdapter.mHolderView.isAttachedToWindow()) {
+            mIsProgressBarVisible = true;
+        }
+        mIsProgressBarVisible = visible;
+        mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.GONE);
+        mDivider.setVisibility(mIsProgressBarVisible ? View.GONE : View.VISIBLE);
+        mInternetDialogSubTitle.setText(getSubtitleText());
+    }
+
+    private boolean shouldShowMobileDialog() {
+        boolean flag = Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA,
+                false);
+        if (mInternetDialogController.isMobileDataEnabled() && !flag) {
+            return true;
+        }
+        return false;
+    }
+
+    private void showTurnOffMobileDialog() {
+        CharSequence carrierName =
+                mSubscriptionManager.getDefaultDataSubscriptionInfo().getCarrierName();
+        boolean isInService = mInternetDialogController.isVoiceStateInService();
+        if (TextUtils.isEmpty(carrierName) || !isInService) {
+            carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
+        }
+        mAlertDialog = new Builder(mContext)
+                .setTitle(R.string.mobile_data_disable_title)
+                .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
+                .setNegativeButton(android.R.string.cancel, (d, w) -> {
+                    mMobileDataToggle.setChecked(true);
+                })
+                .setPositiveButton(
+                        com.android.internal.R.string.alert_windows_notification_turn_off_action,
+                        (d, w) -> {
+                            mInternetDialogController.setMobileDataEnabled(mContext,
+                                    mDefaultDataSubId, false, false);
+                            mMobileDataToggle.setChecked(false);
+                            Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
+                        })
+                .create();
+        mAlertDialog.setOnCancelListener(dialog -> mMobileDataToggle.setChecked(true));
+        mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
+        SystemUIDialog.registerDismissListener(mAlertDialog);
+        SystemUIDialog.setWindowOnTop(mAlertDialog);
+        mAlertDialog.show();
+    }
+
+    @Override
+    public void onRefreshCarrierInfo() {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    public void onSimStateChanged() {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    public void onSubscriptionsChanged(int defaultDataSubId) {
+        mDefaultDataSubId = defaultDataSubId;
+        mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    public void onServiceStateChanged(ServiceState serviceState) {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    @WorkerThread
+    public void onDataConnectionStateChanged(int state, int networkType) {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
+        mHandler.post(() -> updateDialog());
+    }
+
+    @Override
+    @WorkerThread
+    public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
+            @Nullable WifiEntry connectedEntry) {
+        mConnectedWifiEntry = connectedEntry;
+        mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+        mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
+        mHandler.post(() -> {
+            mAdapter.notifyDataSetChanged();
+            updateDialog();
+        });
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (mAlertDialog != null && !mAlertDialog.isShowing()) {
+            if (!hasFocus && isShowing()) {
+                dismiss();
+            }
+        }
+    }
+
+    public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "The Internet dialog became visible on the screen.")
+        INTERNET_DIALOG_SHOW(843);
+
+        private final int mId;
+
+        InternetDialogEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
new file mode 100644
index 0000000..dfe78de8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -0,0 +1,939 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.dialog;
+
+import static com.android.settingslib.mobile.MobileMappings.getIconKey;
+import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.provider.Settings;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyDisplayInfo;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.DeviceInfoUtils;
+import com.android.settingslib.Utils;
+import com.android.settingslib.graph.SignalDrawable;
+import com.android.settingslib.mobile.MobileMappings;
+import com.android.settingslib.net.SignalStrengthUtil;
+import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.wifitrackerlib.MergedCarrierEntry;
+import com.android.wifitrackerlib.WifiEntry;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+public class InternetDialogController implements WifiEntry.DisconnectCallback,
+        NetworkController.AccessPointController.AccessPointCallback {
+
+    private static final String TAG = "InternetDialogController";
+    private static final String ACTION_NETWORK_PROVIDER_SETTINGS =
+            "android.settings.NETWORK_PROVIDER_SETTINGS";
+    private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
+    public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
+    public static final int NO_CELL_DATA_TYPE_ICON = 0;
+    private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off;
+    private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT =
+            R.string.tap_a_network_to_connect;
+    private static final int SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS =
+            R.string.unlock_to_view_networks;
+    private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS =
+            R.string.wifi_empty_list_wifi_on;
+    private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE =
+            R.string.non_carrier_network_unavailable;
+    private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE =
+            R.string.all_network_unavailable;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    static final int MAX_WIFI_ENTRY_COUNT = 4;
+
+    private WifiManager mWifiManager;
+    private Context mContext;
+    private SubscriptionManager mSubscriptionManager;
+    private TelephonyManager mTelephonyManager;
+    private ConnectivityManager mConnectivityManager;
+    private TelephonyDisplayInfo mTelephonyDisplayInfo =
+            new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                    TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
+    private Handler mHandler;
+    private MobileMappings.Config mConfig = null;
+    private Executor mExecutor;
+    private AccessPointController mAccessPointController;
+    private IntentFilter mConnectionStateFilter;
+    private InternetDialogCallback mCallback;
+    private WifiEntry mConnectedEntry;
+    private int mWifiEntriesCount;
+    private UiEventLogger mUiEventLogger;
+    private BroadcastDispatcher mBroadcastDispatcher;
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private GlobalSettings mGlobalSettings;
+    private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+    @VisibleForTesting
+    protected ActivityStarter mActivityStarter;
+    @VisibleForTesting
+    protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
+    @VisibleForTesting
+    protected InternetTelephonyCallback mInternetTelephonyCallback;
+    @VisibleForTesting
+    protected WifiUtils.InternetIconInjector mWifiIconInjector;
+    @VisibleForTesting
+    protected boolean mCanConfigWifi;
+    @VisibleForTesting
+    protected KeyguardStateController mKeyguardStateController;
+
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onRefreshCarrierInfo() {
+                    mCallback.onRefreshCarrierInfo();
+                }
+
+                @Override
+                public void onSimStateChanged(int subId, int slotId, int simState) {
+                    mCallback.onSimStateChanged();
+                }
+            };
+
+    protected List<SubscriptionInfo> getSubscriptionInfo() {
+        return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
+    }
+
+    @Inject
+    public InternetDialogController(@NonNull Context context, UiEventLogger uiEventLogger,
+            ActivityStarter starter, AccessPointController accessPointController,
+            SubscriptionManager subscriptionManager, TelephonyManager telephonyManager,
+            @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
+            @Main Handler handler, @Main Executor mainExecutor,
+            BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor,
+            GlobalSettings globalSettings, KeyguardStateController keyguardStateController) {
+        if (DEBUG) {
+            Log.d(TAG, "Init InternetDialogController");
+        }
+        mHandler = handler;
+        mExecutor = mainExecutor;
+        mContext = context;
+        mGlobalSettings = globalSettings;
+        mWifiManager = wifiManager;
+        mTelephonyManager = telephonyManager;
+        mConnectivityManager = connectivityManager;
+        mSubscriptionManager = subscriptionManager;
+        mBroadcastDispatcher = broadcastDispatcher;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mKeyguardStateController = keyguardStateController;
+        mConnectionStateFilter = new IntentFilter();
+        mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+        mUiEventLogger = uiEventLogger;
+        mActivityStarter = starter;
+        mAccessPointController = accessPointController;
+        mConfig = MobileMappings.Config.readConfig(mContext);
+        mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext);
+    }
+
+    void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
+        if (DEBUG) {
+            Log.d(TAG, "onStart");
+        }
+        mCallback = callback;
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+        mAccessPointController.addAccessPointCallback(this);
+        mBroadcastDispatcher.registerReceiver(mConnectionStateReceiver, mConnectionStateFilter,
+                mExecutor);
+        // Listen the subscription changes
+        mOnSubscriptionsChangedListener = new InternetOnSubscriptionChangedListener();
+        mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
+                mOnSubscriptionsChangedListener);
+        mDefaultDataSubId = getDefaultDataSubscriptionId();
+        if (DEBUG) {
+            Log.d(TAG, "Init, SubId: " + mDefaultDataSubId);
+        }
+        mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
+        mInternetTelephonyCallback = new InternetTelephonyCallback();
+        mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback);
+        // Listen the connectivity changes
+        mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build(), new DataConnectivityListener(), mHandler);
+        mCanConfigWifi = canConfigWifi;
+        scanWifiAccessPoints();
+    }
+
+    void onStop() {
+        if (DEBUG) {
+            Log.d(TAG, "onStop");
+        }
+        mBroadcastDispatcher.unregisterReceiver(mConnectionStateReceiver);
+        mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
+        mSubscriptionManager.removeOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangedListener);
+        mAccessPointController.removeAccessPointCallback(this);
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
+    }
+
+    @VisibleForTesting
+    boolean isAirplaneModeEnabled() {
+        return mGlobalSettings.getInt(Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+    }
+
+    @VisibleForTesting
+    protected int getDefaultDataSubscriptionId() {
+        return mSubscriptionManager.getDefaultDataSubscriptionId();
+    }
+
+    @VisibleForTesting
+    protected Intent getSettingsIntent() {
+        return new Intent(ACTION_NETWORK_PROVIDER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    protected Intent getWifiDetailsSettingsIntent() {
+        String key = mConnectedEntry == null ? null : mConnectedEntry.getKey();
+        if (TextUtils.isEmpty(key)) {
+            if (DEBUG) {
+                Log.d(TAG, "connected entry's key is empty");
+            }
+            return null;
+        }
+        return WifiUtils.getWifiDetailsSettingsIntent(key);
+    }
+
+    CharSequence getDialogTitleText() {
+        if (isAirplaneModeEnabled()) {
+            return mContext.getText(R.string.airplane_mode);
+        }
+        return mContext.getText(R.string.quick_settings_internet_label);
+    }
+
+    CharSequence getSubtitleText(boolean isProgressBarVisible) {
+        if (isAirplaneModeEnabled()) {
+            return null;
+        }
+
+        if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) {
+            // When the airplane mode is off and Wi-Fi is disabled.
+            //   Sub-Title: Wi-Fi is off
+            if (DEBUG) {
+                Log.d(TAG, "Airplane mode off + Wi-Fi off.");
+            }
+            return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF);
+        }
+
+        if (isDeviceLocked()) {
+            // When the device is locked.
+            //   Sub-Title: Unlock to view networks
+            if (DEBUG) {
+                Log.d(TAG, "The device is locked.");
+            }
+            return mContext.getText(SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS);
+        }
+
+        if (mConnectedEntry != null || mWifiEntriesCount > 0) {
+            return mCanConfigWifi ? mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT) : null;
+        }
+
+        if (mCanConfigWifi && isProgressBarVisible) {
+            // When the Wi-Fi scan result callback is received
+            //   Sub-Title: Searching for networks...
+            return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS);
+        }
+
+        // Sub-Title:
+        // show non_carrier_network_unavailable
+        //   - while Wi-Fi on + no Wi-Fi item
+        //   - while Wi-Fi on + no Wi-Fi item + mobile data off
+        // show all_network_unavailable:
+        //   - while Wi-Fi on + no Wi-Fi item + no carrier item
+        //   - while Wi-Fi on + no Wi-Fi item + service is out of service
+        //   - while Wi-Fi on + no Wi-Fi item + mobile data on + no carrier data.
+        if (DEBUG) {
+            Log.d(TAG, "No Wi-Fi item.");
+        }
+        if (!hasCarrier() || (!isVoiceStateInService() && !isDataStateInService())) {
+            if (DEBUG) {
+                Log.d(TAG, "No carrier or service is out of service.");
+            }
+            return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
+        }
+
+        if (mCanConfigWifi && !isMobileDataEnabled()) {
+            if (DEBUG) {
+                Log.d(TAG, "Mobile data off");
+            }
+            return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+        }
+
+        if (!activeNetworkIsCellular()) {
+            if (DEBUG) {
+                Log.d(TAG, "No carrier data.");
+            }
+            return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
+        }
+
+        if (mCanConfigWifi) {
+            return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+        }
+        return null;
+    }
+
+    Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) {
+        final Drawable drawable =
+                mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel());
+        if (drawable == null) {
+            return null;
+        }
+        drawable.setTint(mContext.getColor(R.color.connected_network_primary_color));
+        return drawable;
+    }
+
+    boolean isNightMode() {
+        return (mContext.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+    }
+
+    Drawable getSignalStrengthDrawable() {
+        Drawable drawable = mContext.getDrawable(
+                R.drawable.ic_signal_strength_zero_bar_no_internet);
+        try {
+            if (mTelephonyManager == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "TelephonyManager is null");
+                }
+                return drawable;
+            }
+
+            if (isDataStateInService() || isVoiceStateInService()) {
+                AtomicReference<Drawable> shared = new AtomicReference<>();
+                shared.set(getSignalStrengthDrawableWithLevel());
+                drawable = shared.get();
+            }
+
+            drawable.setTint(activeNetworkIsCellular() ? mContext.getColor(
+                    R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+                    mContext, android.R.attr.textColorTertiary));
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+        return drawable;
+    }
+
+    /**
+     * To get the signal bar icon with level.
+     *
+     * @return The Drawable which is a signal bar icon with level.
+     */
+    Drawable getSignalStrengthDrawableWithLevel() {
+        final SignalStrength strength = mTelephonyManager.getSignalStrength();
+        int level = (strength == null) ? 0 : strength.getLevel();
+        int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+        if (mSubscriptionManager != null && shouldInflateSignalStrength(mDefaultDataSubId)) {
+            level += 1;
+            numLevels += 1;
+        }
+        return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, false);
+    }
+
+    Drawable getSignalStrengthIcon(Context context, int level, int numLevels,
+            int iconType, boolean cutOut) {
+        Log.d(TAG, "getSignalStrengthIcon");
+        final SignalDrawable signalDrawable = new SignalDrawable(context);
+        signalDrawable.setLevel(
+                SignalDrawable.getState(level, numLevels, cutOut));
+
+        // Make the network type drawable
+        final Drawable networkDrawable =
+                iconType == NO_CELL_DATA_TYPE_ICON
+                        ? EMPTY_DRAWABLE
+                        : context.getResources().getDrawable(iconType, context.getTheme());
+
+        // Overlay the two drawables
+        final Drawable[] layers = {networkDrawable, signalDrawable};
+        final int iconSize =
+                context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size);
+
+        final LayerDrawable icons = new LayerDrawable(layers);
+        // Set the network type icon at the top left
+        icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT);
+        // Set the signal strength icon at the bottom right
+        icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT);
+        icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize);
+        icons.setTintList(Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+        return icons;
+    }
+
+    private boolean shouldInflateSignalStrength(int subId) {
+        return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId);
+    }
+
+    private CharSequence getUniqueSubscriptionDisplayName(int subscriptionId, Context context) {
+        final Map<Integer, CharSequence> displayNames = getUniqueSubscriptionDisplayNames(context);
+        return displayNames.getOrDefault(subscriptionId, "");
+    }
+
+    private Map<Integer, CharSequence> getUniqueSubscriptionDisplayNames(Context context) {
+        class DisplayInfo {
+            public SubscriptionInfo subscriptionInfo;
+            public CharSequence originalName;
+            public CharSequence uniqueName;
+        }
+
+        // Map of SubscriptionId to DisplayName
+        final Supplier<Stream<DisplayInfo>> originalInfos =
+                () -> getSubscriptionInfo()
+                        .stream()
+                        .filter(i -> {
+                            // Filter out null values.
+                            return (i != null && i.getDisplayName() != null);
+                        })
+                        .map(i -> {
+                            DisplayInfo info = new DisplayInfo();
+                            info.subscriptionInfo = i;
+                            info.originalName = i.getDisplayName().toString().trim();
+                            return info;
+                        });
+
+        // A Unique set of display names
+        Set<CharSequence> uniqueNames = new HashSet<>();
+        // Return the set of duplicate names
+        final Set<CharSequence> duplicateOriginalNames = originalInfos.get()
+                .filter(info -> !uniqueNames.add(info.originalName))
+                .map(info -> info.originalName)
+                .collect(Collectors.toSet());
+
+        // If a display name is duplicate, append the final 4 digits of the phone number.
+        // Creates a mapping of Subscription id to original display name + phone number display name
+        final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> {
+            if (duplicateOriginalNames.contains(info.originalName)) {
+                // This may return null, if the user cannot view the phone number itself.
+                final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(context,
+                        info.subscriptionInfo);
+                String lastFourDigits = "";
+                if (phoneNumber != null) {
+                    lastFourDigits = (phoneNumber.length() > 4)
+                            ? phoneNumber.substring(phoneNumber.length() - 4) : phoneNumber;
+                }
+
+                if (TextUtils.isEmpty(lastFourDigits)) {
+                    info.uniqueName = info.originalName;
+                } else {
+                    info.uniqueName = info.originalName + " " + lastFourDigits;
+                }
+
+            } else {
+                info.uniqueName = info.originalName;
+            }
+            return info;
+        });
+
+        // Check uniqueness a second time.
+        // We might not have had permission to view the phone numbers.
+        // There might also be multiple phone numbers whose last 4 digits the same.
+        uniqueNames.clear();
+        final Set<CharSequence> duplicatePhoneNames = uniqueInfos.get()
+                .filter(info -> !uniqueNames.add(info.uniqueName))
+                .map(info -> info.uniqueName)
+                .collect(Collectors.toSet());
+
+        return uniqueInfos.get().map(info -> {
+            if (duplicatePhoneNames.contains(info.uniqueName)) {
+                info.uniqueName = info.originalName + " "
+                        + info.subscriptionInfo.getSubscriptionId();
+            }
+            return info;
+        }).collect(Collectors.toMap(
+                info -> info.subscriptionInfo.getSubscriptionId(),
+                info -> info.uniqueName));
+    }
+
+    CharSequence getMobileNetworkTitle() {
+        return getUniqueSubscriptionDisplayName(mDefaultDataSubId, mContext);
+    }
+
+    String getMobileNetworkSummary() {
+        String description = getNetworkTypeDescription(mContext, mConfig,
+                mTelephonyDisplayInfo, mDefaultDataSubId);
+        return getMobileSummary(mContext, mTelephonyManager, description);
+    }
+
+    /**
+     * Get currently description of mobile network type.
+     */
+    private String getNetworkTypeDescription(Context context, MobileMappings.Config config,
+            TelephonyDisplayInfo telephonyDisplayInfo, int subId) {
+        String iconKey = getIconKey(telephonyDisplayInfo);
+
+        if (mapIconSets(config) == null || mapIconSets(config).get(iconKey) == null) {
+            if (DEBUG) {
+                Log.d(TAG, "The description of network type is empty.");
+            }
+            return "";
+        }
+
+        int resId = mapIconSets(config).get(iconKey).dataContentDescription;
+        return resId != 0
+                ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : "";
+    }
+
+    private String getMobileSummary(Context context, TelephonyManager telephonyManager,
+            String networkTypeDescription) {
+        if (!isMobileDataEnabled()) {
+            return context.getString(R.string.mobile_data_off_summary);
+        }
+        if (!isDataStateInService()) {
+            return context.getString(R.string.mobile_data_no_connection);
+        }
+        String summary = networkTypeDescription;
+        if (activeNetworkIsCellular()) {
+            summary = context.getString(R.string.preference_summary_default_combination,
+                    context.getString(R.string.mobile_data_connection_active),
+                    networkTypeDescription);
+        }
+        return summary;
+    }
+
+    void launchNetworkSetting() {
+        mCallback.dismissDialog();
+        mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0);
+    }
+
+    void launchWifiNetworkDetailsSetting() {
+        Intent intent = getWifiDetailsSettingsIntent();
+        if (intent != null) {
+            mCallback.dismissDialog();
+            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
+        }
+    }
+
+    void connectCarrierNetwork() {
+        final MergedCarrierEntry mergedCarrierEntry =
+                mAccessPointController.getMergedCarrierEntry();
+        if (mergedCarrierEntry != null && mergedCarrierEntry.canConnect()) {
+            mergedCarrierEntry.connect(null /* ConnectCallback */);
+        }
+    }
+
+    WifiManager getWifiManager() {
+        return mWifiManager;
+    }
+
+    TelephonyManager getTelephonyManager() {
+        return mTelephonyManager;
+    }
+
+    SubscriptionManager getSubscriptionManager() {
+        return mSubscriptionManager;
+    }
+
+    /**
+     * @return whether there is the carrier item in the slice.
+     */
+    boolean hasCarrier() {
+        if (mSubscriptionManager == null) {
+            if (DEBUG) {
+                Log.d(TAG, "SubscriptionManager is null, can not check carrier.");
+            }
+            return false;
+        }
+
+        if (isAirplaneModeEnabled() || mTelephonyManager == null
+                || mSubscriptionManager.getActiveSubscriptionIdList().length <= 0) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Return {@code true} if mobile data is enabled
+     */
+    boolean isMobileDataEnabled() {
+        if (mTelephonyManager == null || !mTelephonyManager.isDataEnabled()) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set whether to enable data for {@code subId}, also whether to disable data for other
+     * subscription
+     */
+    void setMobileDataEnabled(Context context, int subId, boolean enabled,
+            boolean disableOtherSubscriptions) {
+        if (mTelephonyManager == null) {
+            if (DEBUG) {
+                Log.d(TAG, "TelephonyManager is null, can not set mobile data.");
+            }
+            return;
+        }
+
+        if (mSubscriptionManager == null) {
+            if (DEBUG) {
+                Log.d(TAG, "SubscriptionManager is null, can not set mobile data.");
+            }
+            return;
+        }
+
+        mTelephonyManager.setDataEnabled(enabled);
+        if (disableOtherSubscriptions) {
+            final List<SubscriptionInfo> subInfoList =
+                    mSubscriptionManager.getActiveSubscriptionInfoList();
+            if (subInfoList != null) {
+                for (SubscriptionInfo subInfo : subInfoList) {
+                    // We never disable mobile data for opportunistic subscriptions.
+                    if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) {
+                        context.getSystemService(TelephonyManager.class).createForSubscriptionId(
+                                subInfo.getSubscriptionId()).setDataEnabled(false);
+                    }
+                }
+            }
+        }
+    }
+
+    boolean isDataStateInService() {
+        final ServiceState serviceState = mTelephonyManager.getServiceState();
+        NetworkRegistrationInfo regInfo =
+                (serviceState == null) ? null : serviceState.getNetworkRegistrationInfo(
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        return (regInfo == null) ? false : regInfo.isRegistered();
+    }
+
+    boolean isVoiceStateInService() {
+        if (mTelephonyManager == null) {
+            if (DEBUG) {
+                Log.d(TAG, "TelephonyManager is null, can not detect voice state.");
+            }
+            return false;
+        }
+
+        final ServiceState serviceState = mTelephonyManager.getServiceState();
+        return serviceState != null
+                && serviceState.getState() == serviceState.STATE_IN_SERVICE;
+    }
+
+    public boolean isDeviceLocked() {
+        return !mKeyguardStateController.isUnlocked();
+    }
+
+    boolean activeNetworkIsCellular() {
+        if (mConnectivityManager == null) {
+            if (DEBUG) {
+                Log.d(TAG, "ConnectivityManager is null, can not check active network.");
+            }
+            return false;
+        }
+
+        final Network activeNetwork = mConnectivityManager.getActiveNetwork();
+        if (activeNetwork == null) {
+            return false;
+        }
+        final NetworkCapabilities networkCapabilities =
+                mConnectivityManager.getNetworkCapabilities(activeNetwork);
+        if (networkCapabilities == null) {
+            return false;
+        }
+        return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+    }
+
+    boolean connect(WifiEntry ap) {
+        if (ap == null) {
+            if (DEBUG) {
+                Log.d(TAG, "No Wi-Fi ap to connect.");
+            }
+            return false;
+        }
+
+        if (ap.getWifiConfiguration() != null) {
+            if (DEBUG) {
+                Log.d(TAG, "connect networkId=" + ap.getWifiConfiguration().networkId);
+            }
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "connect to unsaved network " + ap.getTitle());
+            }
+        }
+        ap.connect(new WifiEntryConnectCallback(mActivityStarter, mContext, ap));
+        return false;
+    }
+
+    static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback {
+        final ActivityStarter mActivityStarter;
+        final Context mContext;
+        final WifiEntry mWifiEntry;
+
+        WifiEntryConnectCallback(ActivityStarter activityStarter, Context context,
+                WifiEntry connectWifiEntry) {
+            mActivityStarter = activityStarter;
+            mContext = context;
+            mWifiEntry = connectWifiEntry;
+        }
+
+        @Override
+        public void onConnectResult(@ConnectStatus int status) {
+            if (DEBUG) {
+                Log.d(TAG, "onConnectResult " + status);
+            }
+
+            if (status == WifiEntry.ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
+                final Intent intent = new Intent("com.android.settings.WIFI_DIALOG")
+                        .putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey());
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mActivityStarter.startActivity(intent, true);
+            } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
+                Toast.makeText(mContext, R.string.wifi_failed_connect_message,
+                        Toast.LENGTH_SHORT).show();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "connect failure reason=" + status);
+                }
+            }
+        }
+    }
+
+    private void scanWifiAccessPoints() {
+        if (mCanConfigWifi) {
+            mAccessPointController.scanForAccessPoints();
+        }
+    }
+
+    @Override
+    @WorkerThread
+    public void onAccessPointsChanged(List<WifiEntry> accessPoints) {
+        if (!mCanConfigWifi) {
+            return;
+        }
+
+        if (accessPoints == null || accessPoints.size() == 0) {
+            mConnectedEntry = null;
+            mWifiEntriesCount = 0;
+            if (mCallback != null) {
+                mCallback.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */);
+            }
+            return;
+        }
+
+        boolean hasConnectedWifi = false;
+        final int accessPointSize = accessPoints.size();
+        for (int i = 0; i < accessPointSize; i++) {
+            WifiEntry wifiEntry = accessPoints.get(i);
+            if (wifiEntry.isDefaultNetwork() && wifiEntry.hasInternetAccess()) {
+                mConnectedEntry = wifiEntry;
+                hasConnectedWifi = true;
+                break;
+            }
+        }
+        if (!hasConnectedWifi) {
+            mConnectedEntry = null;
+        }
+
+        int count = MAX_WIFI_ENTRY_COUNT;
+        if (hasCarrier()) {
+            count -= 1;
+        }
+        if (hasConnectedWifi) {
+            count -= 1;
+        }
+        final List<WifiEntry> wifiEntries = accessPoints.stream()
+                .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork()
+                        || !wifiEntry.hasInternetAccess()))
+                .limit(count)
+                .collect(Collectors.toList());
+        mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+
+        if (mCallback != null) {
+            mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry);
+        }
+    }
+
+    @Override
+    public void onSettingsActivityTriggered(Intent settingsIntent) {
+    }
+
+    @Override
+    public void onDisconnectResult(int status) {
+    }
+
+    private class InternetTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.DataConnectionStateListener,
+            TelephonyCallback.DisplayInfoListener,
+            TelephonyCallback.ServiceStateListener,
+            TelephonyCallback.SignalStrengthsListener {
+
+        @Override
+        public void onServiceStateChanged(@NonNull ServiceState serviceState) {
+            mCallback.onServiceStateChanged(serviceState);
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            mCallback.onDataConnectionStateChanged(state, networkType);
+        }
+
+        @Override
+        public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) {
+            mCallback.onSignalStrengthsChanged(signalStrength);
+        }
+
+        @Override
+        public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
+            mTelephonyDisplayInfo = telephonyDisplayInfo;
+            mCallback.onDisplayInfoChanged(telephonyDisplayInfo);
+        }
+    }
+
+    private class InternetOnSubscriptionChangedListener
+            extends SubscriptionManager.OnSubscriptionsChangedListener {
+        InternetOnSubscriptionChangedListener() {
+            super();
+        }
+
+        @Override
+        public void onSubscriptionsChanged() {
+            updateListener();
+        }
+    }
+
+    private class DataConnectivityListener extends ConnectivityManager.NetworkCallback {
+        @Override
+        @WorkerThread
+        public void onCapabilitiesChanged(@NonNull Network network,
+                @NonNull NetworkCapabilities networkCapabilities) {
+            if (mCanConfigWifi) {
+                for (int transport : networkCapabilities.getTransportTypes()) {
+                    if (transport == NetworkCapabilities.TRANSPORT_WIFI) {
+                        scanWifiAccessPoints();
+                        break;
+                    }
+                }
+            }
+            final Network activeNetwork = mConnectivityManager.getActiveNetwork();
+            if (activeNetwork != null && activeNetwork.equals(network)) {
+                // update UI
+                mCallback.onCapabilitiesChanged(network, networkCapabilities);
+            }
+        }
+    }
+
+    private final BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+                if (DEBUG) {
+                    Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
+                }
+                updateListener();
+            }
+        }
+    };
+
+    private void updateListener() {
+        int defaultDataSubId = getDefaultDataSubscriptionId();
+        if (mDefaultDataSubId == getDefaultDataSubscriptionId()) {
+            if (DEBUG) {
+                Log.d(TAG, "DDS: no change");
+            }
+            return;
+        }
+
+        mDefaultDataSubId = defaultDataSubId;
+        if (DEBUG) {
+            Log.d(TAG, "DDS: defaultDataSubId:" + mDefaultDataSubId);
+        }
+        if (SubscriptionManager.isUsableSubscriptionId(mDefaultDataSubId)) {
+            mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
+            mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
+            mTelephonyManager.registerTelephonyCallback(mHandler::post,
+                    mInternetTelephonyCallback);
+            mCallback.onSubscriptionsChanged(mDefaultDataSubId);
+        }
+    }
+
+    public WifiUtils.InternetIconInjector getWifiIconInjector() {
+        return mWifiIconInjector;
+    }
+
+    interface InternetDialogCallback {
+
+        void onRefreshCarrierInfo();
+
+        void onSimStateChanged();
+
+        void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities);
+
+        void onSubscriptionsChanged(int defaultDataSubId);
+
+        void onServiceStateChanged(ServiceState serviceState);
+
+        void onDataConnectionStateChanged(int state, int networkType);
+
+        void onSignalStrengthsChanged(SignalStrength signalStrength);
+
+        void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo);
+
+        void dismissDialog();
+
+        void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
+                @Nullable WifiEntry connectedEntry);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
new file mode 100644
index 0000000..11c6980
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.tiles.dialog
+
+import android.content.Context
+import android.os.Handler
+import android.util.Log
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import javax.inject.Inject
+
+private const val TAG = "InternetDialogFactory"
+private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+
+/**
+ * Factory to create [InternetDialog] objects.
+ */
+@SysUISingleton
+class InternetDialogFactory @Inject constructor(
+    @Main private val handler: Handler,
+    private val internetDialogController: InternetDialogController,
+    private val context: Context,
+    private val uiEventLogger: UiEventLogger
+) {
+    companion object {
+        var internetDialog: InternetDialog? = null
+    }
+
+    /** Creates a [InternetDialog]. */
+    fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) {
+        if (internetDialog != null) {
+            if (DEBUG) {
+                Log.d(TAG, "InternetDialog is showing, do not create it twice.")
+            }
+            return
+        } else {
+            internetDialog = InternetDialog(context, this, internetDialogController,
+                    canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler)
+            internetDialog?.show()
+        }
+    }
+
+    fun destroyDialog() {
+        if (DEBUG) {
+            Log.d(TAG, "destroyDialog")
+        }
+        internetDialog = null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java
new file mode 100644
index 0000000..6aaba99
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java
@@ -0,0 +1,14 @@
+package com.android.systemui.qs.tiles.dialog;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+public class InternetDialogUtil {
+
+    public static boolean isProviderModelEnabled(Context context) {
+        if (context == null) {
+            return false;
+        }
+        return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 0eaef72..31d51f1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -154,6 +154,7 @@
     @Override
     public void onStart() {
         super.onStart();
+        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_STARTED);
 
         if (mPreview.getDrawable() != null) {
             // We already have an image, so no need to try to load again.
@@ -245,6 +246,8 @@
     }
 
     private void onCachedImageLoaded(ImageLoader.Result imageResult) {
+        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED);
+
         BitmapDrawable drawable = new BitmapDrawable(getResources(), imageResult.bitmap);
         mPreview.setImageDrawable(drawable);
         mPreview.setAlpha(1f);
@@ -282,6 +285,8 @@
             finish();
         }
         if (isFinishing()) {
+            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_FINISHED);
+
             if (mScrollCaptureResponse != null) {
                 mScrollCaptureResponse.close();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 16872b0..cab2168 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -660,7 +660,7 @@
                     + mLastScrollCaptureResponse.getWindowTitle() + "]");
 
             final ScrollCaptureResponse response = mLastScrollCaptureResponse;
-            mScreenshotView.showScrollChip(/* onClick */ () -> {
+            mScreenshotView.showScrollChip(response.getPackageName(), /* onClick */ () -> {
                 DisplayMetrics displayMetrics = new DisplayMetrics();
                 getDefaultDisplay().getRealMetrics(displayMetrics);
                 Bitmap newScreenshot = captureScreenshot(
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 5cf0188..169b28c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -71,7 +71,19 @@
     @UiEvent(doc = "User has shared a long screenshot")
     SCREENSHOT_LONG_SCREENSHOT_SHARE(689),
     @UiEvent(doc = "User has sent a long screenshot to the editor")
-    SCREENSHOT_LONG_SCREENSHOT_EDIT(690);
+    SCREENSHOT_LONG_SCREENSHOT_EDIT(690),
+    @UiEvent(doc = "A long screenshot capture has started")
+    SCREENSHOT_LONG_SCREENSHOT_STARTED(880),
+    @UiEvent(doc = "The long screenshot capture failed")
+    SCREENSHOT_LONG_SCREENSHOT_FAILURE(881),
+    @UiEvent(doc = "The long screenshot capture completed successfully")
+    SCREENSHOT_LONG_SCREENSHOT_COMPLETED(882),
+    @UiEvent(doc = "Long screenshot editor activity started")
+    SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_STARTED(889),
+    @UiEvent(doc = "Long screenshot editor activity loaded a previously saved screenshot")
+    SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED(890),
+    @UiEvent(doc = "Long screenshot editor activity finished")
+    SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_FINISHED(891);
 
     private final int mId;
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index e9e62f2..e5e690bcb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -242,19 +242,21 @@
     /**
      * Called to display the scroll action chip when support is detected.
      *
+     * @param packageName the owning package of the window to be captured
      * @param onClick the action to take when the chip is clicked.
      */
-    public void showScrollChip(Runnable onClick) {
+    public void showScrollChip(String packageName, Runnable onClick) {
         if (DEBUG_SCROLL) {
             Log.d(TAG, "Showing Scroll option");
         }
-        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION);
+        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION, 0, packageName);
         mScrollChip.setVisibility(VISIBLE);
         mScrollChip.setOnClickListener((v) -> {
             if (DEBUG_INPUT) {
                 Log.d(TAG, "scroll chip tapped");
             }
-            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED);
+            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED, 0,
+                    packageName);
             onClick.run();
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 6dc6874..ef7355a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -28,6 +28,7 @@
 import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
@@ -61,6 +62,7 @@
     private final Context mContext;
     private final Executor mBgExecutor;
     private final ImageTileSet mImageTileSet;
+    private final UiEventLogger mEventLogger;
     private final ScrollCaptureClient mClient;
 
     private Completer<LongScreenshot> mCaptureCompleter;
@@ -69,6 +71,7 @@
     private Session mSession;
     private ListenableFuture<CaptureResult> mTileFuture;
     private ListenableFuture<Void> mEndFuture;
+    private String mWindowOwner;
 
     static class LongScreenshot {
         private final ImageTileSet mImageTileSet;
@@ -135,11 +138,12 @@
 
     @Inject
     ScrollCaptureController(Context context, @Background Executor bgExecutor,
-            ScrollCaptureClient client, ImageTileSet imageTileSet) {
+            ScrollCaptureClient client, ImageTileSet imageTileSet, UiEventLogger logger) {
         mContext = context;
         mBgExecutor = bgExecutor;
         mClient = client;
         mImageTileSet = imageTileSet;
+        mEventLogger = logger;
     }
 
     @VisibleForTesting
@@ -157,6 +161,7 @@
     ListenableFuture<LongScreenshot> run(ScrollCaptureResponse response) {
         return CallbackToFutureAdapter.getFuture(completer -> {
             mCaptureCompleter = completer;
+            mWindowOwner = response.getPackageName();
             mBgExecutor.execute(() -> {
                 float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(),
                         SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT);
@@ -173,11 +178,13 @@
             if (LogConfig.DEBUG_SCROLL) {
                 Log.d(TAG, "got session " + mSession);
             }
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_STARTED, 0, mWindowOwner);
             requestNextTile(0);
         } catch (InterruptedException | ExecutionException e) {
             // Failure to start, propagate to caller
             Log.e(TAG, "session start failed!");
             mCaptureCompleter.setException(e);
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_FAILURE, 0, mWindowOwner);
         }
     }
 
@@ -297,6 +304,11 @@
         if (LogConfig.DEBUG_SCROLL) {
             Log.d(TAG, "finishCapture()");
         }
+        if (mImageTileSet.getHeight() > 0) {
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_COMPLETED, 0, mWindowOwner);
+        } else {
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_FAILURE, 0, mWindowOwner);
+        }
         mEndFuture = mSession.end();
         mEndFuture.addListener(() -> {
             if (LogConfig.DEBUG_SCROLL) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 503b5c0..1431c9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -821,7 +821,7 @@
         }
     }
 
-    private void showTryFingerprintMsg() {
+    private void showTryFingerprintMsg(String a11yString) {
         if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
             // if udfps available, there will always be a tappable affordance to unlock
             // For example, the lock icon
@@ -833,6 +833,11 @@
         } else {
             showTransientIndication(R.string.keyguard_try_fingerprint);
         }
+
+        // Although we suppress face auth errors visually, we still announce them for a11y
+        if (!TextUtils.isEmpty(a11yString)) {
+            mLockScreenIndicationView.announceForAccessibility(a11yString);
+        }
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -913,7 +918,7 @@
             } else if (mKeyguardUpdateMonitor.isScreenOn()) {
                 if (biometricSourceType == BiometricSourceType.FACE
                         && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
-                    showTryFingerprintMsg();
+                    showTryFingerprintMsg(helpString);
                     return;
                 }
                 showTransientIndication(helpString, false /* isError */, showActionToUnlock);
@@ -933,7 +938,7 @@
                     && shouldSuppressFaceMsgAndShowTryFingerprintMsg()
                     && !mStatusBarKeyguardViewManager.isBouncerShowing()
                     && mKeyguardUpdateMonitor.isScreenOn()) {
-                showTryFingerprintMsg();
+                showTryFingerprintMsg(errString);
                 return;
             }
             if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -942,7 +947,7 @@
                 if (!mStatusBarKeyguardViewManager.isBouncerShowing()
                         && mKeyguardUpdateMonitor.isUdfpsEnrolled()
                         && mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
-                    showTryFingerprintMsg();
+                    showTryFingerprintMsg(errString);
                 } else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
                     mStatusBarKeyguardViewManager.showBouncerMessage(
                             mContext.getResources().getString(R.string.keyguard_unlock_press),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 538db61..21ed9da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -149,7 +149,10 @@
  */
 class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
 
-    lateinit var revealAmountListener: Consumer<Float>
+    /**
+     * Listener that is called if the scrim's opaqueness changes
+     */
+    lateinit var isScrimOpaqueChangedListener: Consumer<Boolean>
 
     /**
      * How much of the underlying views are revealed, in percent. 0 means they will be completely
@@ -161,7 +164,7 @@
                 field = value
 
                 revealEffect.setRevealAmountOnScrim(value, this)
-                revealAmountListener.accept(value)
+                updateScrimOpaque()
                 invalidate()
             }
         }
@@ -201,6 +204,31 @@
         }
 
     /**
+     * Is the scrim currently fully opaque
+     */
+    var isScrimOpaque = false
+        private set(value) {
+            if (field != value) {
+                field = value
+                isScrimOpaqueChangedListener.accept(field)
+            }
+        }
+
+    private fun updateScrimOpaque() {
+        isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE
+    }
+
+    override fun setAlpha(alpha: Float) {
+        super.setAlpha(alpha)
+        updateScrimOpaque()
+    }
+
+    override fun setVisibility(visibility: Int) {
+        super.setVisibility(visibility)
+        updateScrimOpaque()
+    }
+
+    /**
      * Paint used to draw a transparent-to-white radial gradient. This will be scaled and translated
      * via local matrix in [onDraw] so we never need to construct a new shader.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index f0d779c..6ea79af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -182,10 +182,10 @@
     default void setFaceAuthDisplayBrightness(float brightness) {}
 
     /**
-     * How much {@link LightRevealScrim} obscures the UI.
-     * @param amount 0 when opaque, 1 when not transparent
+     * If {@link LightRevealScrim} obscures the UI.
+     * @param opaque if the scrim is opaque
      */
-    default void setLightRevealScrimAmount(float amount) {}
+    default void setLightRevealScrimOpaque(boolean opaque) {}
 
     /**
      * Custom listener to pipe data back to plugins about whether or not the status bar would be
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
index 4a467ce..d01fc93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
@@ -104,7 +104,7 @@
         // the active effect area. Values here should be kept in sync with the
         // animation implementation in the ripple shader.
         val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
-                (1 - rippleShader.progress)) * radius * 1.5f
+                (1 - rippleShader.progress)) * radius * 2
         canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 86c90c7..9eb95c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -28,15 +27,12 @@
 import com.android.systemui.statusbar.notification.stack.ViewState;
 
 public class FooterView extends StackScrollerDecorView {
-    private final int mClearAllTopPadding;
     private FooterViewButton mDismissButton;
     private FooterViewButton mManageButton;
     private boolean mShowHistory;
 
     public FooterView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mClearAllTopPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.clear_all_padding_top);
     }
 
     @Override
@@ -55,11 +51,6 @@
         mManageButton = findViewById(R.id.manage_text);
     }
 
-    public void setTextColor(@ColorInt int color) {
-        mManageButton.setTextColor(color);
-        mDismissButton.setTextColor(color);
-    }
-
     public void setManageButtonClickListener(OnClickListener listener) {
         mManageButton.setOnClickListener(listener);
     }
@@ -95,21 +86,25 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        int textColor = getResources().getColor(R.color.notif_pill_text);
-        Resources.Theme theme = getContext().getTheme();
-        mDismissButton.setBackground(
-                getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
-        mDismissButton.setTextColor(textColor);
-        mManageButton.setBackground(
-                getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
-        mManageButton = findViewById(R.id.manage_text);
+        updateColors();
         mDismissButton.setText(R.string.clear_all_notifications_text);
-        mManageButton.setTextColor(textColor);
         mDismissButton.setContentDescription(
                 mContext.getString(R.string.accessibility_clear_all));
         showHistory(mShowHistory);
     }
 
+    /**
+     * Update the text and background colors for the current color palette and night mode setting.
+     */
+    public void updateColors() {
+        Resources.Theme theme = mContext.getTheme();
+        int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+        mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+        mDismissButton.setTextColor(textColor);
+        mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+        mManageButton.setTextColor(textColor);
+    }
+
     @Override
     public ExpandableViewState createExpandableViewState() {
         return new FooterViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index dba3401..9c755e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -85,23 +85,26 @@
     }
 
     /**
-     * Set the content of this view to be visible in an animated way.
-     *
-     * @param contentVisible True if the content should be visible or false if it should be hidden.
+     * @param visible True if we should animate contents visible
      */
-    public void setContentVisible(boolean contentVisible) {
-        setContentVisible(contentVisible, true /* animate */);
+    public void setContentVisible(boolean visible) {
+        setContentVisible(visible, true /* animate */, null /* runAfter */);
     }
+
     /**
-     * Set the content of this view to be visible.
-     * @param contentVisible True if the content should be visible or false if it should be hidden.
-     * @param animate Should an animation be performed.
+     * @param visible True if the contents should be visible
+     * @param animate True if we should fade to new visibility
+     * @param runAfter Runnable to run after visibility updates
      */
-    private void setContentVisible(boolean contentVisible, boolean animate) {
-        if (mContentVisible != contentVisible) {
+    public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) {
+        if (mContentVisible != visible) {
             mContentAnimating = animate;
-            mContentVisible = contentVisible;
-            setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable);
+            mContentVisible = visible;
+            Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> {
+                mContentVisibilityEndRunnable.run();
+                runAfter.run();
+            };
+            setViewVisible(mContent, visible, animate, endRunnable);
         }
 
         if (!mContentAnimating) {
@@ -113,6 +116,10 @@
         return mContentVisible;
     }
 
+    public void setVisible(boolean nowVisible, boolean animate) {
+        setVisible(nowVisible, animate, null);
+    }
+
     /**
      * Make this view visible. If {@code false} is passed, the view will fade out it's content
      * and set the view Visibility to GONE. If only the content should be changed
@@ -121,7 +128,7 @@
      * @param nowVisible should the view be visible
      * @param animate should the change be animated.
      */
-    public void setVisible(boolean nowVisible, boolean animate) {
+    public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) {
         if (mIsVisible != nowVisible) {
             mIsVisible = nowVisible;
             if (animate) {
@@ -132,10 +139,10 @@
                 } else {
                     setWillBeGone(true);
                 }
-                setContentVisible(nowVisible, true /* animate */);
+                setContentVisible(nowVisible, true /* animate */, runAfter);
             } else {
                 setVisibility(nowVisible ? VISIBLE : GONE);
-                setContentVisible(nowVisible, false /* animate */);
+                setContentVisible(nowVisible, false /* animate */, runAfter);
                 setWillBeGone(false);
                 notifyHeightChanged(false /* needsAnimation */);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 23aefd9..594afce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -46,6 +46,7 @@
     private Runnable mRoundingChangedCallback;
     private ExpandableNotificationRow mTrackedHeadsUp;
     private float mAppearFraction;
+    private boolean mIsDismissAllInProgress;
 
     private ExpandableView mSwipedView = null;
     private ExpandableView mViewBeforeSwipedView = null;
@@ -162,6 +163,10 @@
         }
     }
 
+    void setDismissAllInProgress(boolean isClearingAll) {
+        mIsDismissAllInProgress = isClearingAll;
+    }
+
     private float getRoundness(ExpandableView view, boolean top) {
         if (view == null) {
             return 0f;
@@ -171,6 +176,11 @@
                 || view == mViewAfterSwipedView) {
             return 1f;
         }
+        if (view instanceof ExpandableNotificationRow
+                && ((ExpandableNotificationRow) view).canViewBeDismissed()
+                && mIsDismissAllInProgress) {
+            return 1.0f;
+        }
         if ((view.isPinned()
                 || (view.isHeadsUpAnimatingAway()) && !mExpanded)) {
             return 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 289c32f..a771274 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -144,6 +144,10 @@
     private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean(
             "persist.debug.nssl.dismiss", false /* default */);
 
+    // Delay in milli-seconds before shade closes for clear all.
+    private final int DELAY_BEFORE_SHADE_CLOSE = 200;
+    private boolean mShadeNeedsToClose = false;
+
     private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
     private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f;
     private static final float RUBBER_BAND_FACTOR_ON_PANEL_EXPAND = 0.21f;
@@ -259,7 +263,6 @@
     protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
     private boolean mDismissAllInProgress;
-    private boolean mFadeNotificationsOnDismiss;
     private FooterDismissListener mFooterDismissListener;
     private boolean mFlingAfterUpEvent;
 
@@ -1192,7 +1195,7 @@
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private void clampScrollPosition() {
         int scrollRange = getScrollRange();
-        if (scrollRange < mOwnScrollY) {
+        if (scrollRange < mOwnScrollY && !mAmbientState.isDismissAllInProgress()) {
             boolean animateStackY = false;
             if (scrollRange < getScrollAmountToScrollBoundary()
                     && mAnimateStackYForContentHeightChange) {
@@ -1708,6 +1711,11 @@
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
+        if (child instanceof SectionHeaderView) {
+             ((StackScrollerDecorView) child).setContentVisible(
+                     false /* visible */, true /* animate */, endRunnable);
+             return;
+        }
         mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
                 true /* isDismissAll */);
     }
@@ -4050,6 +4058,19 @@
         runAnimationFinishedRunnables();
         clearTransient();
         clearHeadsUpDisappearRunning();
+
+        if (mAmbientState.isDismissAllInProgress()) {
+            setDismissAllInProgress(false);
+
+            if (mShadeNeedsToClose) {
+                mShadeNeedsToClose = false;
+                postDelayed(
+                        () -> {
+                            mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+                        },
+                        DELAY_BEFORE_SHADE_CLOSE /* delayMillis */);
+            }
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4231,7 +4252,7 @@
         final @ColorInt int textColor =
                 Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
         mSectionsManager.setHeaderForegroundColor(textColor);
-        mFooterView.setTextColor(textColor);
+        mFooterView.updateColors();
         mEmptyShadeView.setTextColor(textColor);
     }
 
@@ -4407,6 +4428,7 @@
     public void setDismissAllInProgress(boolean dismissAllInProgress) {
         mDismissAllInProgress = dismissAllInProgress;
         mAmbientState.setDismissAllInProgress(dismissAllInProgress);
+        mController.getNoticationRoundessManager().setDismissAllInProgress(dismissAllInProgress);
         handleDismissAllClipping();
     }
 
@@ -4947,64 +4969,129 @@
         mHeadsUpAppearanceController = headsUpAppearanceController;
     }
 
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    @VisibleForTesting
-    void clearNotifications(@SelectedRows int selection, boolean closeShade) {
-        // animate-swipe all dismissable notifications, then animate the shade closed
-        int numChildren = getChildCount();
+    private boolean isVisible(View child) {
+        boolean hasClipBounds = child.getClipBounds(mTmpRect);
+        return child.getVisibility() == View.VISIBLE
+                && (!hasClipBounds || mTmpRect.height() > 0);
+    }
 
-        final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
-        final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
-        for (int i = 0; i < numChildren; i++) {
-            final View child = getChildAt(i);
-            if (child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                boolean parentVisible = false;
-                boolean hasClipBounds = child.getClipBounds(mTmpRect);
-                if (includeChildInDismissAll(row, selection)) {
-                    viewsToRemove.add(row);
-                    if (child.getVisibility() == View.VISIBLE
-                            && (!hasClipBounds || mTmpRect.height() > 0)) {
-                        viewsToHide.add(child);
-                        parentVisible = true;
-                    }
-                } else if (child.getVisibility() == View.VISIBLE
-                        && (!hasClipBounds || mTmpRect.height() > 0)) {
-                    parentVisible = true;
-                }
-                List<ExpandableNotificationRow> children = row.getAttachedChildren();
-                if (children != null) {
-                    for (ExpandableNotificationRow childRow : children) {
-                        if (includeChildInDismissAll(row, selection)) {
-                            viewsToRemove.add(childRow);
-                            if (parentVisible && row.areChildrenExpanded()) {
-                                hasClipBounds = childRow.getClipBounds(mTmpRect);
-                                if (childRow.getVisibility() == View.VISIBLE
-                                        && (!hasClipBounds || mTmpRect.height() > 0)) {
-                                    viewsToHide.add(childRow);
-                                }
-                            }
+    private boolean shouldHideParent(View view, @SelectedRows int selection) {
+        final boolean silentSectionWillBeGone =
+                !mController.hasNotifications(ROWS_GENTLE, false /* clearable */);
+
+        // The only SectionHeaderView we have is the silent section header.
+        if (view instanceof SectionHeaderView && silentSectionWillBeGone) {
+            return true;
+        }
+        if (view instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            if (isVisible(row) && includeChildInDismissAll(row, selection)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isChildrenVisible(ExpandableNotificationRow parent) {
+        List<ExpandableNotificationRow> children = parent.getAttachedChildren();
+        return isVisible(parent)
+                && children != null
+                && parent.areChildrenExpanded();
+    }
+
+    // Similar to #getRowsToDismissInBackend, but filters for visible views.
+    private ArrayList<View> getVisibleViewsToAnimateAway(@SelectedRows int selection) {
+        final int viewCount = getChildCount();
+        final ArrayList<View> viewsToHide = new ArrayList<>(viewCount);
+
+        for (int i = 0; i < viewCount; i++) {
+            final View view = getChildAt(i);
+
+            if (shouldHideParent(view, selection)) {
+                viewsToHide.add(view);
+            }
+            if (view instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+
+                if (isChildrenVisible(parent)) {
+                    for (ExpandableNotificationRow child : parent.getAttachedChildren()) {
+                        if (isVisible(child) && includeChildInDismissAll(child, selection)) {
+                            viewsToHide.add(child);
                         }
                     }
                 }
             }
         }
+        return viewsToHide;
+    }
 
+    private ArrayList<ExpandableNotificationRow> getRowsToDismissInBackend(
+            @SelectedRows int selection) {
+        final int childCount = getChildCount();
+        final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(childCount);
+
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (!(view instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+            if (includeChildInDismissAll(parent, selection)) {
+                viewsToRemove.add(parent);
+            }
+            List<ExpandableNotificationRow> children = parent.getAttachedChildren();
+            if (isVisible(parent) && children != null) {
+                for (ExpandableNotificationRow child : children) {
+                    if (includeChildInDismissAll(parent, selection)) {
+                        viewsToRemove.add(child);
+                    }
+                }
+            }
+        }
+        return viewsToRemove;
+    }
+
+    /**
+     * Collects a list of visible rows, and animates them away in a staggered fashion as if they
+     * were dismissed. Notifications are dismissed in the backend via onDismissAllAnimationsEnd.
+     */
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    @VisibleForTesting
+    void clearNotifications(@SelectedRows int selection, boolean closeShade) {
+        // Animate-swipe all dismissable notifications, then animate the shade closed
+        final ArrayList<View> viewsToAnimateAway = getVisibleViewsToAnimateAway(selection);
+        final ArrayList<ExpandableNotificationRow> rowsToDismissInBackend =
+                getRowsToDismissInBackend(selection);
         if (mDismissListener != null) {
             mDismissListener.onDismiss(selection);
         }
-
-        if (viewsToRemove.isEmpty()) {
-            if (closeShade && mShadeController != null) {
-                mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
-            }
+        final Runnable dismissInBackend = () -> {
+            onDismissAllAnimationsEnd(rowsToDismissInBackend, selection);
+        };
+        if (viewsToAnimateAway.isEmpty()) {
+            dismissInBackend.run();
             return;
         }
+        // Disable normal animations
+        setDismissAllInProgress(true);
+        mShadeNeedsToClose = closeShade;
 
-        performDismissAllAnimations(
-                viewsToHide,
-                closeShade,
-                () -> onDismissAllAnimationsEnd(viewsToRemove, selection));
+        // Decrease the delay for every row we animate to give the sense of
+        // accelerating the swipes
+        final int rowDelayDecrement = 5;
+        int currentDelay = 60;
+        int totalDelay = 0;
+        final int numItems = viewsToAnimateAway.size();
+        for (int i = numItems - 1; i >= 0; i--) {
+            View view = viewsToAnimateAway.get(i);
+            Runnable endRunnable = null;
+            if (i == 0) {
+                endRunnable = dismissInBackend;
+            }
+            dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE);
+            currentDelay = Math.max(30, currentDelay - rowDelayDecrement);
+            totalDelay += currentDelay;
+        }
     }
 
     private boolean includeChildInDismissAll(
@@ -5013,63 +5100,6 @@
         return canChildBeDismissed(row) && matchesSelection(row, selection);
     }
 
-    /**
-     * Given a list of rows, animates them away in a staggered fashion as if they were dismissed.
-     * Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete
-     * handler.
-     *
-     * @param hideAnimatedList List of rows to animated away. Should only be views that are
-     *                         currently visible, or else the stagger will look funky.
-     * @param closeShade Whether to close the shade after the stagger animation completes.
-     * @param onAnimationComplete Called after the entire animation completes (including the shade
-     *                            closing if appropriate). The rows must be dismissed for real here.
-     */
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void performDismissAllAnimations(
-            final ArrayList<View> hideAnimatedList,
-            final boolean closeShade,
-            final Runnable onAnimationComplete) {
-
-        final Runnable onSlideAwayAnimationComplete = () -> {
-            if (closeShade) {
-                mShadeController.addPostCollapseAction(() -> {
-                    setDismissAllInProgress(false);
-                    onAnimationComplete.run();
-                });
-                mShadeController.animateCollapsePanels(
-                        CommandQueue.FLAG_EXCLUDE_NONE);
-            } else {
-                setDismissAllInProgress(false);
-                onAnimationComplete.run();
-            }
-        };
-
-        if (hideAnimatedList.isEmpty()) {
-            onSlideAwayAnimationComplete.run();
-            return;
-        }
-
-        // let's disable our normal animations
-        setDismissAllInProgress(true);
-
-        // Decrease the delay for every row we animate to give the sense of
-        // accelerating the swipes
-        int rowDelayDecrement = 10;
-        int currentDelay = 140;
-        int totalDelay = 180;
-        int numItems = hideAnimatedList.size();
-        for (int i = numItems - 1; i >= 0; i--) {
-            View view = hideAnimatedList.get(i);
-            Runnable endRunnable = null;
-            if (i == 0) {
-                endRunnable = onSlideAwayAnimationComplete;
-            }
-            dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE);
-            currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
-            totalDelay += currentDelay;
-        }
-    }
-
     public void setNotificationActivityStarter(
             NotificationActivityStarter notificationActivityStarter) {
         mNotificationActivityStarter = notificationActivityStarter;
@@ -5085,6 +5115,7 @@
                 mFooterDismissListener.onDismiss();
             }
             clearNotifications(ROWS_ALL, true /* closeShade */);
+            footerView.setSecondaryVisible(false /* visible */, true /* animate */);
         });
         footerView.setManageButtonClickListener(v -> {
             mNotificationActivityStarter.startHistoryIntent(v, mFooterView.isHistoryShown());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 9e4adce..faba48f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1122,6 +1122,10 @@
                 mZenModeController.areNotificationsHiddenInShade());
     }
 
+    public boolean areNotificationsHiddenInShade() {
+        return mZenModeController.areNotificationsHiddenInShade();
+    }
+
     public boolean isShowingEmptyShadeView() {
         return mShowEmptyShadeView;
     }
@@ -1170,6 +1174,10 @@
      * Return whether there are any clearable notifications
      */
     public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
+        return hasNotifications(selection, true /* clearable */);
+    }
+
+    public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) {
         if (mDynamicPrivacyController.isInLockedDownShade()) {
             return false;
         }
@@ -1180,8 +1188,11 @@
                 continue;
             }
             final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            if (row.canViewBeDismissed() &&
-                    NotificationStackScrollLayout.matchesSelection(row, selection)) {
+            final boolean matchClearable =
+                    isClearable ? row.canViewBeDismissed() : !row.canViewBeDismissed();
+            final boolean inSection =
+                    NotificationStackScrollLayout.matchesSelection(row, selection);
+            if (matchClearable && inSection) {
                 return true;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 2c810c9..8be5de7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -366,6 +366,20 @@
         return stackHeight / stackEndHeight;
     }
 
+    public boolean hasOngoingNotifs(StackScrollAlgorithmState algorithmState) {
+        for (int i = 0; i < algorithmState.visibleChildren.size(); i++) {
+            View child = algorithmState.visibleChildren.get(i);
+            if (!(child instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            if (!row.canViewBeDismissed()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     // TODO(b/172289889) polish shade open from HUN
     /**
      * Populates the {@link ExpandableViewState} for a single child.
@@ -430,7 +444,9 @@
                         + view.getIntrinsicHeight();
                 final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
                 ((FooterView.FooterViewState) viewState).hideContent =
-                        isShelfShowing || noSpaceForFooter;
+                        isShelfShowing || noSpaceForFooter
+                                || (ambientState.isDismissAllInProgress()
+                                && !hasOngoingNotifs(algorithmState));
             }
         } else {
             if (view != ambientState.getTrackedHeadsUpRow()) {
@@ -467,7 +483,6 @@
                     }
                 }
             }
-
             // Clip height of view right before shelf.
             viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ee12b4b..4466cfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -46,7 +46,7 @@
     public static final int ANIMATION_DURATION_WAKEUP = 500;
     public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
     public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
-    public static final int ANIMATION_DURATION_SWIPE = 260;
+    public static final int ANIMATION_DURATION_SWIPE = 200;
     public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
     public static final int ANIMATION_DURATION_CLOSE_REMOTE_INPUT = 150;
     public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 400;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 5a6db21..36f6c4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -268,6 +268,13 @@
     }
 
     /**
+     * Whether the brightness sensor uses the proximity sensor.
+     */
+    public boolean brightnessUsesProx() {
+        return mResources.getBoolean(R.bool.doze_brightness_uses_prox);
+    }
+
+    /**
      * Callback to listen for DozeParameter changes.
      */
     public void addCallback(Callback callback) {
@@ -303,6 +310,7 @@
         pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
         pw.print("getSelectivelyRegisterSensorsUsingProx(): ");
         pw.println(getSelectivelyRegisterSensorsUsingProx());
+        pw.print("brightnessUsesProx(): "); pw.println(brightnessUsesProx());
     }
 
     interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 0a4e59c..4701d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -203,13 +203,15 @@
     private ControlsListingController.ControlsListingCallback mListingCallback =
             new ControlsListingController.ControlsListingCallback() {
                 public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) {
-                    boolean available = !serviceInfos.isEmpty();
+                    post(() -> {
+                        boolean available = !serviceInfos.isEmpty();
 
-                    if (available != mControlServicesAvailable) {
-                        mControlServicesAvailable = available;
-                        updateControlsVisibility();
-                        updateAffordanceColors();
-                    }
+                        if (available != mControlServicesAvailable) {
+                            mControlServicesAvailable = available;
+                            updateControlsVisibility();
+                            updateAffordanceColors();
+                        }
+                    });
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 246810a..c26782b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -605,12 +605,11 @@
     }
 
     @Override
-    public void setLightRevealScrimAmount(float amount) {
-        boolean lightRevealScrimOpaque = amount == 0;
-        if (mCurrentState.mLightRevealScrimOpaque == lightRevealScrimOpaque) {
+    public void setLightRevealScrimOpaque(boolean opaque) {
+        if (mCurrentState.mLightRevealScrimOpaque == opaque) {
             return;
         }
-        mCurrentState.mLightRevealScrimOpaque = lightRevealScrimOpaque;
+        mCurrentState.mLightRevealScrimOpaque = opaque;
         apply(mCurrentState);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index b5d9bd6..e57e200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -311,6 +311,12 @@
                     // Capture all touch events in always-on.
                     return true;
                 }
+
+                if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
+                    // capture all touches if the alt auth bouncer is showing
+                    return true;
+                }
+
                 boolean intercept = false;
                 if (mNotificationPanelViewController.isFullyExpanded()
                         && mDragDownHelper.isDragDownEnabled()
@@ -338,6 +344,12 @@
                 if (mStatusBarStateController.isDozing()) {
                     handled = !mService.isPulsing();
                 }
+
+                if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
+                    // eat the touch
+                    handled = true;
+                }
+
                 if ((mDragDownHelper.isDragDownEnabled() && !handled)
                         || mDragDownHelper.isDraggingDown()) {
                     // we still want to finish our drag down gesture when locking the screen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 323a112..de0f31d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -1211,10 +1211,14 @@
                 case MotionEvent.ACTION_MOVE:
                     final float h = y - mInitialTouchY;
                     addMovement(event);
-                    if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown) {
+                    final boolean openShadeWithoutHun =
+                            mPanelClosedOnDown && !mCollapsedAndHeadsUpOnDown;
+                    if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown
+                            || openShadeWithoutHun) {
                         float hAbs = Math.abs(h);
                         float touchSlop = getTouchSlop(event);
-                        if ((h < -touchSlop || (mAnimatingOnDown && hAbs > touchSlop))
+                        if ((h < -touchSlop
+                                || ((openShadeWithoutHun || mAnimatingOnDown) && hAbs > touchSlop))
                                 && hAbs > Math.abs(x - mInitialTouchX)) {
                             cancelHeightAnimator();
                             startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
@@ -1227,10 +1231,7 @@
                     mVelocityTracker.clear();
                     break;
             }
-
-            // Finally, if none of the above cases applies, ensure that touches do not get handled
-            // by the contents of a panel that is not showing (a bit of a hack to avoid b/178277858)
-            return (mView.getVisibility() != View.VISIBLE);
+            return false;
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 2c0de62..15b8c67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -279,15 +279,41 @@
     BUBBLE_EXPANDED {
         @Override
         public void prepare(ScrimState previousState) {
-            mFrontTint = Color.TRANSPARENT;
-            mBehindTint = Color.TRANSPARENT;
-            mBubbleTint = Color.BLACK;
+            mBehindAlpha = mClipQsScrim ? 1 : 0;
+            mNotifAlpha = 0;
+            mFrontAlpha = 0;
 
-            mFrontAlpha = 0f;
-            mBehindAlpha = mDefaultScrimAlpha;
+            mAnimationDuration = mKeyguardFadingAway
+                    ? mKeyguardFadingAwayDuration
+                    : StatusBar.FADE_KEYGUARD_DURATION;
+
+            mAnimateChange = !mLaunchingAffordanceWithPreview;
+
+            mFrontTint = Color.TRANSPARENT;
+            mBehindTint = Color.BLACK;
+            mBubbleTint = Color.BLACK;
+            mBlankScreen = false;
+
+            if (previousState == ScrimState.AOD) {
+                // Set all scrims black, before they fade transparent.
+                updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */);
+                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */);
+                if (mScrimForBubble != null) {
+                    updateScrimColor(mScrimForBubble, 1f /* alpha */, Color.BLACK /* tint */);
+                }
+
+                // Scrims should still be black at the end of the transition.
+                mFrontTint = Color.BLACK;
+                mBehindTint = Color.BLACK;
+                mBubbleTint = Color.BLACK;
+                mBlankScreen = true;
+            }
+
+            if (mClipQsScrim) {
+                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+            }
 
             mAnimationDuration = ScrimController.ANIMATION_DURATION;
-            mBlankScreen = false;
         }
     };
 
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 4705a36..d7a359e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1044,7 +1044,7 @@
                 mNotificationShadeWindowViewController,
                 mNotificationPanelViewController,
                 mAmbientIndicationContainer);
-        mDozeParameters.addCallback(this::updateLightRevealScrimVisibility);
+        updateLightRevealScrimVisibility();
 
         mConfigurationController.addCallback(this);
 
@@ -1261,8 +1261,19 @@
         mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront, scrimForBubble);
 
         mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
-        mLightRevealScrim.setRevealAmountListener(
-                mNotificationShadeWindowController::setLightRevealScrimAmount);
+        mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> {
+            Runnable updateOpaqueness = () -> {
+                mNotificationShadeWindowController.setLightRevealScrimOpaque(
+                        mLightRevealScrim.isScrimOpaque());
+            };
+            if (opaque) {
+                // Delay making the view opaque for a frame, because it needs some time to render
+                // otherwise this can lead to a flicker where the scrim doesn't cover the screen
+                mLightRevealScrim.post(updateOpaqueness);
+            } else {
+                updateOpaqueness.run();
+            }
+        });
         mUnlockedScreenOffAnimationController.initialize(this, mLightRevealScrim);
         updateLightRevealScrimVisibility();
 
@@ -4956,11 +4967,5 @@
         }
 
         mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
-        if (mFeatureFlags.useNewLockscreenAnimations()
-                && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
-            mLightRevealScrim.setVisibility(View.VISIBLE);
-        } else {
-            mLightRevealScrim.setVisibility(View.GONE);
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 8a7708a..3653b95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -303,8 +303,10 @@
      * Sets a new alt auth interceptor.
      */
     public void setAlternateAuthInterceptor(@NonNull AlternateAuthInterceptor authInterceptor) {
-        mAlternateAuthInterceptor = authInterceptor;
-        resetAlternateAuth(false);
+        if (!Objects.equals(mAlternateAuthInterceptor, authInterceptor)) {
+            mAlternateAuthInterceptor = authInterceptor;
+            resetAlternateAuth(false);
+        }
     }
 
     private void registerListeners() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 47deb1f..8821de0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -310,17 +310,11 @@
     private void onNotificationRemoved(String key, StatusBarNotification old, int reason) {
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
 
-        if (old != null) {
-            if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
-                    && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
-                if (mStatusBarStateController.getState() == StatusBarState.SHADE
-                        && reason != NotificationListenerService.REASON_CLICK) {
-                    mCommandQueue.animateCollapsePanels();
-                } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
+        if (old != null && CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
+                && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()
+                && mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
                         && !isCollapsing()) {
-                    mStatusBarStateController.setState(StatusBarState.KEYGUARD);
-                }
-            }
+                mStatusBarStateController.setState(StatusBarState.KEYGUARD);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index ab58286..6d6320e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -40,6 +40,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.UserTracker;
+import com.android.wifitrackerlib.MergedCarrierEntry;
 import com.android.wifitrackerlib.WifiEntry;
 import com.android.wifitrackerlib.WifiPickerTracker;
 
@@ -68,6 +69,7 @@
 
     private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>();
     private final UserManager mUserManager;
+    private final UserTracker mUserTracker;
     private final Executor mMainExecutor;
 
     private @Nullable WifiPickerTracker mWifiPickerTracker;
@@ -84,6 +86,7 @@
             WifiPickerTrackerFactory wifiPickerTrackerFactory
     ) {
         mUserManager = userManager;
+        mUserTracker = userTracker;
         mCurrentUser = userTracker.getUserId();
         mMainExecutor = mainExecutor;
         mWifiPickerTrackerFactory = wifiPickerTrackerFactory;
@@ -118,6 +121,11 @@
                 new UserHandle(mCurrentUser));
     }
 
+    public boolean canConfigMobileData() {
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
+                UserHandle.of(mCurrentUser)) && mUserTracker.getUserInfo().isAdmin();
+    }
+
     public void onUserSwitched(int newUserId) {
         mCurrentUser = newUserId;
     }
@@ -157,6 +165,15 @@
     }
 
     @Override
+    public MergedCarrierEntry getMergedCarrierEntry() {
+        if (mWifiPickerTracker == null) {
+            fireAcccessPointsCallback(Collections.emptyList());
+            return null;
+        }
+        return mWifiPickerTracker.getMergedCarrierEntry();
+    }
+
+    @Override
     public int getIcon(WifiEntry ap) {
         int level = ap.getLevel();
         return ICONS[Math.max(0, level)];
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index ef2ca98..eeea699 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -23,6 +23,7 @@
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.wifitrackerlib.MergedCarrierEntry;
 import com.android.wifitrackerlib.WifiEntry;
 
 import java.util.List;
@@ -223,9 +224,11 @@
         void addAccessPointCallback(AccessPointCallback callback);
         void removeAccessPointCallback(AccessPointCallback callback);
         void scanForAccessPoints();
+        MergedCarrierEntry getMergedCarrierEntry();
         int getIcon(WifiEntry ap);
         boolean connect(WifiEntry ap);
         boolean canConfigWifi();
+        boolean canConfigMobileData();
 
         public interface AccessPointCallback {
             void onAccessPointsChanged(List<WifiEntry> accessPoints);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index c49de7a..af0d413 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -68,9 +68,12 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
+import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -191,6 +194,8 @@
     private boolean mUserSetup;
     private boolean mSimDetected;
     private boolean mForceCellularValidated;
+    private InternetDialogFactory mInternetDialogFactory;
+    private Handler mMainHandler;
 
     private ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -221,7 +226,9 @@
             DemoModeController demoModeController,
             CarrierConfigTracker carrierConfigTracker,
             FeatureFlags featureFlags,
-            DumpManager dumpManager) {
+            DumpManager dumpManager,
+            @Main Handler handler,
+            InternetDialogFactory internetDialogFactory) {
         this(context, connectivityManager,
                 telephonyManager,
                 telephonyListenerManager,
@@ -242,6 +249,8 @@
                 featureFlags,
                 dumpManager);
         mReceiverHandler.post(mRegisterListeners);
+        mMainHandler = handler;
+        mInternetDialogFactory = internetDialogFactory;
     }
 
     @VisibleForTesting
@@ -480,6 +489,9 @@
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        if (InternetDialogUtil.isProviderModelEnabled(mContext)) {
+            filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
+        }
         mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
         mListening = true;
 
@@ -788,6 +800,10 @@
                 mConfig = Config.readConfig(mContext);
                 mReceiverHandler.post(this::handleConfigurationChanged);
                 break;
+            case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
+                mMainHandler.post(() -> mInternetDialogFactory.create(true,
+                        mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi()));
+                break;
             default:
                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 84d7c05..5d7d480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -77,7 +77,6 @@
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -204,7 +203,7 @@
         final int stroke = colorized ? mContext.getResources().getDimensionPixelSize(
                 R.dimen.remote_input_view_text_stroke) : 0;
         if (colorized) {
-            final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
+            final boolean dark = Notification.Builder.isColorDark(backgroundColor);
             final int foregroundColor = dark ? Color.WHITE : Color.BLACK;
             final int inverseColor = dark ? Color.BLACK : Color.WHITE;
             editBgColor = backgroundColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 41b1dd1..4e33529 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -628,7 +628,7 @@
         mCurrentBackgroundColor = backgroundColor;
         mCurrentColorized = colorized;
 
-        final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
+        final boolean dark = Notification.Builder.isColorDark(backgroundColor);
 
         mCurrentTextColor = ContrastColorUtil.ensureTextContrast(
                 dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
new file mode 100644
index 0000000..ae9d9ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.content.Context
+import android.text.StaticLayout
+import android.util.AttributeSet
+import android.widget.TextView
+import com.android.systemui.R
+
+/**
+ * View for showing a date that can toggle between two different formats depending on size.
+ *
+ * If no pattern can fit, it will display empty.
+ *
+ * @see R.styleable.VariableDateView_longDatePattern
+ * @see R.styleable.VariableDateView_shortDatePattern
+ */
+class VariableDateView(context: Context, attrs: AttributeSet) : TextView(context, attrs) {
+
+    val longerPattern: String
+    val shorterPattern: String
+
+    init {
+        val a = context.theme.obtainStyledAttributes(
+                attrs,
+                R.styleable.VariableDateView,
+                0, 0)
+        longerPattern = a.getString(R.styleable.VariableDateView_longDatePattern)
+                ?: context.getString(R.string.system_ui_date_pattern)
+        shorterPattern = a.getString(R.styleable.VariableDateView_shortDatePattern)
+                ?: context.getString(R.string.abbrev_month_day_no_year)
+
+        a.recycle()
+    }
+
+    /**
+     * Freeze the pattern switching
+     *
+     * Use during animations if the container will change its size but this view should not change
+     */
+    var freezeSwitching = false
+
+    private var onMeasureListener: OnMeasureListener? = null
+
+    fun onAttach(listener: OnMeasureListener?) {
+        onMeasureListener = listener
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        val availableWidth = MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingEnd
+        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED && !freezeSwitching) {
+            onMeasureListener?.onMeasureAction(availableWidth)
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+    }
+
+    fun getDesiredWidthForText(text: CharSequence): Float {
+        return StaticLayout.getDesiredWidth(text, paint)
+    }
+
+    interface OnMeasureListener {
+        fun onMeasureAction(availableWidth: Int)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
new file mode 100644
index 0000000..99d84c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.icu.text.DateFormat
+import android.icu.text.DisplayContext
+import android.icu.util.Calendar
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.UserHandle
+import android.text.TextUtils
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dependency
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.util.ViewController
+import com.android.systemui.util.time.SystemClock
+import java.text.FieldPosition
+import java.text.ParsePosition
+import java.util.Date
+import java.util.Locale
+import javax.inject.Inject
+import javax.inject.Named
+
+@VisibleForTesting
+internal fun getTextForFormat(date: Date?, format: DateFormat): String {
+    return if (format === EMPTY_FORMAT) { // Check if same object
+        ""
+    } else format.format(date)
+}
+
+@VisibleForTesting
+internal fun getFormatFromPattern(pattern: String?): DateFormat {
+    if (TextUtils.equals(pattern, "")) {
+        return EMPTY_FORMAT
+    }
+    val l = Locale.getDefault()
+    val format = DateFormat.getInstanceForSkeleton(pattern, l)
+    format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE)
+    return format
+}
+
+private val EMPTY_FORMAT: DateFormat = object : DateFormat() {
+    override fun format(
+        cal: Calendar,
+        toAppendTo: StringBuffer,
+        fieldPosition: FieldPosition
+    ): StringBuffer? {
+        return null
+    }
+
+    override fun parse(text: String, cal: Calendar, pos: ParsePosition) {}
+}
+
+private const val DEBUG = false
+private const val TAG = "VariableDateViewController"
+
+class VariableDateViewController(
+    private val systemClock: SystemClock,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val timeTickHandler: Handler,
+    view: VariableDateView
+) : ViewController<VariableDateView>(view) {
+
+    private var dateFormat: DateFormat? = null
+    private var datePattern = view.longerPattern
+        set(value) {
+            if (field == value) return
+            field = value
+            dateFormat = null
+            if (isAttachedToWindow) {
+                post(::updateClock)
+            }
+        }
+    private var lastWidth = Integer.MAX_VALUE
+    private var lastText = ""
+    private var currentTime = Date()
+
+    // View class easy accessors
+    private val longerPattern: String
+        get() = mView.longerPattern
+    private val shorterPattern: String
+        get() = mView.shorterPattern
+    private fun post(block: () -> Unit) = mView.handler?.post(block)
+
+    private val intentReceiver: BroadcastReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            // If the handler is null, it means we received a broadcast while the view has not
+            // finished being attached or in the process of being detached.
+            // In that case, do not post anything.
+            val handler = mView.handler ?: return
+            val action = intent.action
+            if (
+                    Intent.ACTION_TIME_TICK == action ||
+                    Intent.ACTION_TIME_CHANGED == action ||
+                    Intent.ACTION_TIMEZONE_CHANGED == action ||
+                    Intent.ACTION_LOCALE_CHANGED == action
+            ) {
+                if (
+                        Intent.ACTION_LOCALE_CHANGED == action ||
+                        Intent.ACTION_TIMEZONE_CHANGED == action
+                ) {
+                    // need to get a fresh date format
+                    handler.post { dateFormat = null }
+                }
+                handler.post(::updateClock)
+            }
+        }
+    }
+
+    private val onMeasureListener = object : VariableDateView.OnMeasureListener {
+        override fun onMeasureAction(availableWidth: Int) {
+            if (availableWidth != lastWidth) {
+                // maybeChangeFormat will post if the pattern needs to change.
+                maybeChangeFormat(availableWidth)
+                lastWidth = availableWidth
+            }
+        }
+    }
+
+    override fun onViewAttached() {
+        val filter = IntentFilter().apply {
+            addAction(Intent.ACTION_TIME_TICK)
+            addAction(Intent.ACTION_TIME_CHANGED)
+            addAction(Intent.ACTION_TIMEZONE_CHANGED)
+            addAction(Intent.ACTION_LOCALE_CHANGED)
+        }
+
+        broadcastDispatcher.registerReceiver(intentReceiver, filter,
+                HandlerExecutor(timeTickHandler), UserHandle.SYSTEM)
+
+        post(::updateClock)
+        mView.onAttach(onMeasureListener)
+    }
+
+    override fun onViewDetached() {
+        dateFormat = null
+        mView.onAttach(null)
+        broadcastDispatcher.unregisterReceiver(intentReceiver)
+    }
+
+    private fun updateClock() {
+        if (dateFormat == null) {
+            dateFormat = getFormatFromPattern(datePattern)
+        }
+
+        currentTime.time = systemClock.currentTimeMillis()
+
+        val text = getTextForFormat(currentTime, dateFormat!!)
+        if (text != lastText) {
+            mView.setText(text)
+            lastText = text
+        }
+    }
+
+    private fun maybeChangeFormat(availableWidth: Int) {
+        if (mView.freezeSwitching ||
+                availableWidth > lastWidth && datePattern == longerPattern ||
+                availableWidth < lastWidth && datePattern == ""
+        ) {
+            // Nothing to do
+            return
+        }
+        if (DEBUG) Log.d(TAG, "Width changed. Maybe changing pattern")
+        // Start with longer pattern and see what fits
+        var text = getTextForFormat(currentTime, getFormatFromPattern(longerPattern))
+        var length = mView.getDesiredWidthForText(text)
+        if (length <= availableWidth) {
+            changePattern(longerPattern)
+            return
+        }
+
+        text = getTextForFormat(currentTime, getFormatFromPattern(shorterPattern))
+        length = mView.getDesiredWidthForText(text)
+        if (length <= availableWidth) {
+            changePattern(shorterPattern)
+            return
+        }
+
+        changePattern("")
+    }
+
+    private fun changePattern(newPattern: String) {
+        if (newPattern.equals(datePattern)) return
+        if (DEBUG) Log.d(TAG, "Changing pattern to $newPattern")
+        datePattern = newPattern
+    }
+
+    class Factory @Inject constructor(
+        private val systemClock: SystemClock,
+        private val broadcastDispatcher: BroadcastDispatcher,
+        @Named(Dependency.TIME_TICK_HANDLER_NAME) private val handler: Handler
+    ) {
+        fun create(view: VariableDateView): VariableDateViewController {
+            return VariableDateViewController(
+                    systemClock,
+                    broadcastDispatcher,
+                    handler,
+                    view
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 81999b5..6af49ff 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -530,6 +530,10 @@
             mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
                     managedProfiles);
         }
+        onOverlaysApplied();
+    }
+
+    protected void onOverlaysApplied() {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 98b4209e..bfa50bc 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.TextView;
@@ -63,6 +64,8 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        getWindow().addPrivateFlags(
+                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         Intent intent = getIntent();
         mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
         mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 90e022a5..bd11039 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -87,15 +87,23 @@
                     && (mLastPrimaryEvent == null
                     || !mLastPrimaryEvent.getBelow()
                     || !event.getBelow())) {
-                mSecondaryThresholdSensor.pause();
+                chooseSensor();
                 if (mLastPrimaryEvent == null || !mLastPrimaryEvent.getBelow()) {
                     // Only check the secondary as long as the primary thinks we're near.
-                    mCancelSecondaryRunnable = null;
+                    if (mCancelSecondaryRunnable != null) {
+                        mCancelSecondaryRunnable.run();
+                        mCancelSecondaryRunnable = null;
+                    }
                     return;
                 } else {
                     // Check this sensor again in a moment.
-                    mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(
-                            mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS);
+                    mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(() -> {
+                        // This is safe because we know that mSecondaryThresholdSensor
+                        // is loaded, otherwise we wouldn't be here.
+                        mPrimaryThresholdSensor.pause();
+                        mSecondaryThresholdSensor.resume();
+                    },
+                        SECONDARY_PING_INTERVAL_MS);
                 }
             }
             logDebug("Secondary sensor event: " + event.getBelow() + ".");
@@ -159,12 +167,8 @@
      * of what is reported by the primary sensor.
      */
     public void setSecondarySafe(boolean safe) {
-        mSecondarySafe = safe;
-        if (!mSecondarySafe) {
-            mSecondaryThresholdSensor.pause();
-        } else {
-            mSecondaryThresholdSensor.resume();
-        }
+        mSecondarySafe = mSecondaryThresholdSensor.isLoaded() && safe;
+        chooseSensor();
     }
 
     /**
@@ -209,16 +213,30 @@
             return;
         }
         if (!mInitializedListeners) {
+            mPrimaryThresholdSensor.pause();
+            mSecondaryThresholdSensor.pause();
             mPrimaryThresholdSensor.register(mPrimaryEventListener);
-            if (!mSecondarySafe) {
-                mSecondaryThresholdSensor.pause();
-            }
             mSecondaryThresholdSensor.register(mSecondaryEventListener);
             mInitializedListeners = true;
         }
         logDebug("Registering sensor listener");
-        mPrimaryThresholdSensor.resume();
+
         mRegistered = true;
+        chooseSensor();
+    }
+
+    private void chooseSensor() {
+        mExecution.assertIsMainThread();
+        if (!mRegistered || mPaused || mListeners.isEmpty()) {
+            return;
+        }
+        if (mSecondarySafe) {
+            mSecondaryThresholdSensor.resume();
+            mPrimaryThresholdSensor.pause();
+        } else {
+            mPrimaryThresholdSensor.resume();
+            mSecondaryThresholdSensor.pause();
+        }
     }
 
     /**
@@ -312,7 +330,7 @@
         }
 
         if (!mSecondarySafe && !event.getBelow()) {
-            mSecondaryThresholdSensor.pause();
+            chooseSensor();
         }
 
         mLastEvent = event;
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index f1c687f..2c9c980 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -93,6 +93,13 @@
         <activity android:name="com.android.systemui.screenshot.RecyclerViewActivity"
                   android:exported="false" />
 
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbPermissionActivityTest$UsbPermissionActivityTestable"
+                  android:exported="false"
+                  android:theme="@style/Theme.SystemUI.Dialog.Alert"
+                  android:finishOnCloseSystemDialogs="true"
+                  android:excludeFromRecents="true" />
+
         <provider
             android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
             tools:replace="android:authorities"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 2120b0e..f64d517 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -69,6 +69,7 @@
 import com.android.systemui.util.concurrency.FakeExecution;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.time.SystemClock;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -147,6 +148,8 @@
     private Handler mHandler;
     @Mock
     private ConfigurationController mConfigurationController;
+    @Mock
+    private SystemClock mSystemClock;
 
     private FakeExecutor mFgExecutor;
 
@@ -229,7 +232,8 @@
                 mKeyguardBypassController,
                 mDisplayManager,
                 mHandler,
-                mConfigurationController);
+                mConfigurationController,
+                mSystemClock);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -413,6 +417,21 @@
     }
 
     @Test
+    public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
+        // GIVEN overlay was showing and the udfps bouncer is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
+
+        // WHEN the overlay is hidden
+        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+        mFgExecutor.runAllReady();
+
+        // THEN the udfps bouncer is reset
+        verify(mStatusBarKeyguardViewManager).resetAlternateAuth(eq(true));
+    }
+
+    @Test
     public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
                 IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 47e060e..96c201f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -18,9 +18,9 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeast;
-
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -89,6 +90,7 @@
     private ConfigurationController mConfigurationController;
     @Mock
     private UdfpsController mUdfpsController;
+    private FakeSystemClock mSystemClock = new FakeSystemClock();
 
     private UdfpsKeyguardViewController mController;
 
@@ -124,6 +126,7 @@
                 mKeyguardViewMediator,
                 mLockscreenShadeTransitionController,
                 mConfigurationController,
+                mSystemClock,
                 mKeyguardStateController,
                 mUdfpsController);
     }
@@ -299,6 +302,59 @@
     }
 
     @Test
+    public void testHiddenUdfpsBouncerOnTouchOutside_nothingHappens() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureAltAuthInterceptor();
+
+        // GIVEN udfps bouncer isn't showing
+        mAltAuthInterceptor.hideAlternateAuthBouncer();
+
+        // WHEN touch is observed outside the view
+        mController.onTouchOutsideView();
+
+        // THEN bouncer / alt auth methods are never called
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+        verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean());
+    }
+
+    @Test
+    public void testShowingUdfpsBouncerOnTouchOutsideWithinThreshold_nothingHappens() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureAltAuthInterceptor();
+
+        // GIVEN udfps bouncer is showing
+        mAltAuthInterceptor.showAlternateAuthBouncer();
+
+        // WHEN touch is observed outside the view 200ms later (just within threshold)
+        mSystemClock.advanceTime(200);
+        mController.onTouchOutsideView();
+
+        // THEN bouncer / alt auth methods are never called because not enough time has passed
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+        verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean());
+    }
+
+    @Test
+    public void testShowingUdfpsBouncerOnTouchOutsideAboveThreshold_showInputBouncer() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureAltAuthInterceptor();
+
+        // GIVEN udfps bouncer is showing
+        mAltAuthInterceptor.showAlternateAuthBouncer();
+
+        // WHEN touch is observed outside the view 205ms later
+        mSystemClock.advanceTime(205);
+        mController.onTouchOutsideView();
+
+        // THEN show the bouncer and reset alt auth
+        verify(mStatusBarKeyguardViewManager).showBouncer(eq(true));
+        verify(mStatusBarKeyguardViewManager).resetAlternateAuth(anyBoolean());
+    }
+
+    @Test
     public void testFadeInWithStatusBarExpansion() {
         // GIVEN view is attached
         mController.onViewAttached();
@@ -342,6 +398,8 @@
         mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
     }
 
+
+
     private void captureKeyguardStateControllerCallback() {
         verify(mKeyguardStateController).addCallback(
                 mKeyguardStateControllerCallbackCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index d6226aa..a32cb9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -43,6 +43,7 @@
         when(params.singleTapUsesProx()).thenReturn(true);
         when(params.longPressUsesProx()).thenReturn(true);
         when(params.getQuickPickupAodDuration()).thenReturn(500);
+        when(params.brightnessUsesProx()).thenReturn(true);
 
         doneHolder[0] = true;
         return params;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 4e8b59c..deb7d31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -29,6 +29,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -47,6 +48,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -82,6 +84,8 @@
     WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock
     DozeParameters mDozeParameters;
+    @Mock
+    DockManager mDockManager;
     private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
     private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor);
 
@@ -109,7 +113,7 @@
         mSensor = fakeSensorManager.getFakeLightSensor();
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */,
-                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager);
 
         mScreen.onScreenState(Display.STATE_ON);
     }
@@ -157,6 +161,67 @@
     }
 
     @Test
+    public void testAodDocked_doNotSelectivelyUseProx_usesLightSensor() {
+        // GIVEN the device doesn't need to selectively register for prox sensors and
+        // brightness sensor uses prox
+        when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false);
+        when(mDozeParameters.brightnessUsesProx()).thenReturn(true);
+
+        // GIVEN the device is docked and the display state changes to ON
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScreen.onScreenState(Display.STATE_ON);
+        waitForSensorManager();
+
+        // WHEN new sensor event sent
+        mSensor.sendSensorEvent(3);
+
+        // THEN brightness is updated
+        assertEquals(3, mServiceFake.screenBrightness);
+    }
+
+    @Test
+    public void testAodDocked_brightnessDoesNotUseProx_usesLightSensor() {
+        // GIVEN the device doesn't need to selectively register for prox sensors but
+        // the brightness sensor doesn't use prox
+        when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true);
+        when(mDozeParameters.brightnessUsesProx()).thenReturn(false);
+
+        // GIVEN the device is docked and the display state changes to ON
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScreen.onScreenState(Display.STATE_ON);
+        waitForSensorManager();
+
+        // WHEN new sensor event sent
+        mSensor.sendSensorEvent(3);
+
+        // THEN brightness is updated
+        assertEquals(3, mServiceFake.screenBrightness);
+    }
+
+
+    @Test
+    public void testAodDocked_noProx_brightnessUsesProx_doNotUseLightSensor() {
+        final int startBrightness = mServiceFake.screenBrightness;
+
+        // GIVEN the device needs to selectively register for prox sensors and
+        // the brightness sensor uses prox
+        when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true);
+        when(mDozeParameters.brightnessUsesProx()).thenReturn(true);
+
+        // GIVEN the device is docked and the display state is on
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScreen.onScreenState(Display.STATE_ON);
+        waitForSensorManager();
+
+        // WHEN new sensor event sent
+        mSensor.sendSensorEvent(3);
+
+        // THEN brightness is NOT changed
+        assertNotSame(3, mServiceFake.screenBrightness);
+        assertEquals(startBrightness, mServiceFake.screenBrightness);
+    }
+
+    @Test
     public void testPausingAod_doesNotResetBrightness() throws Exception {
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
@@ -175,7 +240,7 @@
     public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception {
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 Optional.empty() /* sensor */, mDozeHost, null /* handler */,
-                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager);
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE);
         reset(mDozeHost);
@@ -216,7 +281,7 @@
     public void testNullSensor() throws Exception {
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 Optional.empty() /* sensor */, mDozeHost, null /* handler */,
-                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 0c94f09..5c4c27c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -88,7 +88,7 @@
     private FakeSettings mFakeSettings = new FakeSettings();
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
-    private DozeSensors mDozeSensors;
+    private TestableDozeSensors mDozeSensors;
     private TriggerSensor mSensorTap;
 
     @Before
@@ -170,6 +170,94 @@
         assertTrue(mSensorTap.mRequested);
     }
 
+    @Test
+    public void testDozeSensorSetListening() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled */ true,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN we want to listen for the trigger sensor
+        triggerSensor.setListening(true);
+
+        // THEN the sensor is registered
+        assertTrue(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testDozeSensorSettingDisabled() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled*/ false,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN setListening is called
+        triggerSensor.setListening(true);
+
+        // THEN the sensor is not registered
+        assertFalse(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testDozeSensorIgnoreSetting() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor that's
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled*/ false,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // GIVEN sensor is listening
+        triggerSensor.setListening(true);
+
+        // WHEN ignoreSetting is called
+        triggerSensor.ignoreSetting(true);
+
+        // THEN the sensor is registered
+        assertTrue(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testUpdateListeningAfterAlreadyRegistered() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled*/ true,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN setListening is called AND updateListening is called
+        triggerSensor.setListening(true);
+        triggerSensor.updateListening();
+
+        // THEN the sensor is still registered
+        assertTrue(triggerSensor.mRegistered);
+    }
+
     private class TestableDozeSensors extends DozeSensors {
 
         TestableDozeSensors() {
@@ -187,5 +275,17 @@
             }
             mSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap};
         }
+
+        public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled,
+                boolean requiresTouchScreen) {
+            return new TriggerSensor(/* sensor */ sensor,
+                    /* setting name */ "test_setting",
+                    /* settingDefault */ settingEnabled,
+                    /* configured */ true,
+                    /* pulseReason*/ 0,
+                    /* reportsTouchCoordinate*/ false,
+                    requiresTouchScreen,
+                    mDozeLog);
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 578c2d9..509ef82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -51,6 +52,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -112,6 +114,7 @@
     @Mock private Handler mHandler;
     @Mock private UserContextProvider mUserContextProvider;
     @Mock private StatusBar mStatusBar;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private TestableLooper mTestableLooper;
 
@@ -156,7 +159,8 @@
                 mSysUiState,
                 mHandler,
                 mPackageManager,
-                mStatusBar
+                mStatusBar,
+                mKeyguardUpdateMonitor
         );
         mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting();
 
@@ -422,4 +426,31 @@
         restartAction.onLongPress();
         verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
     }
+
+    @Test
+    public void testOnLockScreen_disableSmartLock() {
+        mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+        int user = KeyguardUpdateMonitor.getCurrentUser();
+        doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+        doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+        doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+        doReturn(false).when(mStatusBar).isKeyguardShowing();
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+
+        // When entering power menu from lockscreen, with smart lock enabled
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+        mGlobalActionsDialogLite.showOrHideDialog(true, true);
+
+        // Then smart lock will be disabled
+        verify(mLockPatternUtils).requireCredentialEntry(eq(user));
+
+        // hide dialog again
+        mGlobalActionsDialogLite.showOrHideDialog(true, true);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index 2fa67cc..338bb30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -56,6 +56,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -126,6 +127,7 @@
     @Mock private PackageManager mPackageManager;
     @Mock private SecureSettings mSecureSettings;
     @Mock private StatusBar mStatusBar;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private TestableLooper mTestableLooper;
 
@@ -169,7 +171,8 @@
                 mSysUiState,
                 mHandler,
                 mPackageManager,
-                mStatusBar
+                mStatusBar,
+                mKeyguardUpdateMonitor
         );
         mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index ad08780..31d70f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -67,7 +67,7 @@
 import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
 @SmallTest
 public class KeyguardViewMediatorTest extends SysuiTestCase {
     private KeyguardViewMediator mViewMediator;
@@ -126,7 +126,6 @@
                 mUnlockedScreenOffAnimationController,
                 () -> mNotificationShadeDepthController);
         mViewMediator.start();
-        mViewMediator.onSystemReady();
     }
 
     @Test
@@ -165,8 +164,10 @@
     }
 
     @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
     public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway() {
         // When showing and provisioned
+        mViewMediator.onSystemReady();
         when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
         mViewMediator.setShowingLocked(true);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
new file mode 100644
index 0000000..d279bbb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.os.Vibrator;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.LockIconView;
+import com.android.keyguard.LockIconViewController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class LockIconViewControllerTest extends SysuiTestCase {
+    private @Mock LockIconView mLockIconView;
+    private @Mock Context mContext;
+    private @Mock Resources mResources;
+    private @Mock DisplayMetrics mDisplayMetrics;
+    private @Mock StatusBarStateController mStatusBarStateController;
+    private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private @Mock KeyguardViewController mKeyguardViewController;
+    private @Mock KeyguardStateController mKeyguardStateController;
+    private @Mock FalsingManager mFalsingManager;
+    private @Mock AuthController mAuthController;
+    private @Mock DumpManager mDumpManager;
+    private @Mock AccessibilityManager mAccessibilityManager;
+    private @Mock ConfigurationController mConfigurationController;
+    private @Mock DelayableExecutor mDelayableExecutor;
+    private @Mock Vibrator mVibrator;
+    private @Mock AuthRippleController mAuthRippleController;
+
+    private LockIconViewController mLockIconViewController;
+
+    // Capture listeners so that they can be used to send events
+    @Captor private ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
+            ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+    private View.OnAttachStateChangeListener mAttachListener;
+
+    @Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor;
+    private AuthController.Callback mAuthControllerCallback;
+
+    @Captor private ArgumentCaptor<PointF> mPointCaptor;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mLockIconView.getResources()).thenReturn(mResources);
+        when(mLockIconView.getContext()).thenReturn(mContext);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+
+        mLockIconViewController = new LockIconViewController(
+                mLockIconView,
+                mStatusBarStateController,
+                mKeyguardUpdateMonitor,
+                mKeyguardViewController,
+                mKeyguardStateController,
+                mFalsingManager,
+                mAuthController,
+                mDumpManager,
+                mAccessibilityManager,
+                mConfigurationController,
+                mDelayableExecutor,
+                mVibrator,
+                mAuthRippleController
+        );
+    }
+
+    @Test
+    public void testUpdateFingerprintLocationOnInit() {
+        // GIVEN fp sensor location is available pre-init
+        final PointF udfpsLocation = new PointF(50, 75);
+        final int radius = 33;
+        final FingerprintSensorPropertiesInternal fpProps =
+                new FingerprintSensorPropertiesInternal(
+                        /* sensorId */ 0,
+                        /* strength */ 0,
+                        /* max enrollments per user */ 5,
+                        /* component info */ new ArrayList<>(),
+                        /* sensorType */ 3,
+                        /* resetLockoutRequiresHwToken */ false,
+                        (int) udfpsLocation.x, (int) udfpsLocation.y, radius);
+        when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
+        when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+
+        // WHEN lock icon view controller is initialized and attached
+        mLockIconViewController.init();
+        captureAttachListener();
+        mAttachListener.onViewAttachedToWindow(null);
+
+        // THEN lock icon view location is updated with the same coordinates as fpProps
+        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
+        assertEquals(udfpsLocation, mPointCaptor.getValue());
+    }
+
+    @Test
+    public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() {
+        // GIVEN fp sensor location is not available pre-init
+        when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
+        when(mAuthController.getUdfpsProps()).thenReturn(null);
+        mLockIconViewController.init();
+
+        // GIVEN fp sensor location is available post-init
+        captureAuthControllerCallback();
+        final PointF udfpsLocation = new PointF(50, 75);
+        final int radius = 33;
+        final FingerprintSensorPropertiesInternal fpProps =
+                new FingerprintSensorPropertiesInternal(
+                        /* sensorId */ 0,
+                        /* strength */ 0,
+                        /* max enrollments per user */ 5,
+                        /* component info */ new ArrayList<>(),
+                        /* sensorType */ 3,
+                        /* resetLockoutRequiresHwToken */ false,
+                        (int) udfpsLocation.x, (int) udfpsLocation.y, radius);
+        when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
+        when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+
+        // WHEN all authenticators are registered
+        mAuthControllerCallback.onAllAuthenticatorsRegistered();
+
+        // THEN lock icon view location is updated with the same coordinates as fpProps
+        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
+        assertEquals(udfpsLocation, mPointCaptor.getValue());
+    }
+
+    private void captureAuthControllerCallback() {
+        verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture());
+        mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue();
+    }
+
+    private void captureAttachListener() {
+        verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture());
+        mAttachListener = mAttachCaptor.getValue();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
index de7abf8..922c6b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
@@ -14,13 +14,19 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
 import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
-import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.testing.AndroidTestingRunner;
@@ -28,13 +34,24 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+import java.util.concurrent.Executor;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -43,42 +60,38 @@
 
     private static final int USER = 0;
 
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private QSHost mQSHost;
+    @Mock
+    private DumpManager mDumpManager;
+    @Captor
+    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
+    @Captor
+    private ArgumentCaptor<IntentFilter> mIntentFilterArgumentCaptor;
+
+    private Executor mBackgroundExecutor = Runnable::run; // Direct executor
     private AutoAddTracker mAutoTracker;
+    private SecureSettings mSecureSettings;
 
     @Before
     public void setUp() {
-        Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, "");
-    }
+        MockitoAnnotations.initMocks(this);
 
-    @Test
-    public void testMigration() {
-        Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
-        Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
-        mAutoTracker = new AutoAddTracker(mContext, USER);
+        mSecureSettings = new FakeSettings();
+
+        mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, null, USER);
+
+        mAutoTracker = createAutoAddTracker(USER);
         mAutoTracker.initialize();
-
-        assertTrue(mAutoTracker.isAdded(SAVER));
-        assertTrue(mAutoTracker.isAdded(WORK));
-        assertFalse(mAutoTracker.isAdded(INVERSION));
-
-        // These keys have been removed; retrieving their values should always return the default.
-        assertTrue(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true ));
-        assertFalse(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, false));
-        assertTrue(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, true));
-        assertFalse(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, false));
-
-        mAutoTracker.destroy();
     }
 
     @Test
     public void testChangeFromBackup() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
-
         assertFalse(mAutoTracker.isAdded(SAVER));
 
-        Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, SAVER);
-        mAutoTracker.mObserver.onChange(false);
+        mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, SAVER, USER);
 
         assertTrue(mAutoTracker.isAdded(SAVER));
 
@@ -87,9 +100,6 @@
 
     @Test
     public void testSetAdded() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
-
         assertFalse(mAutoTracker.isAdded(SAVER));
         mAutoTracker.setTileAdded(SAVER);
 
@@ -100,14 +110,12 @@
 
     @Test
     public void testPersist() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
-
         assertFalse(mAutoTracker.isAdded(SAVER));
         mAutoTracker.setTileAdded(SAVER);
 
         mAutoTracker.destroy();
-        mAutoTracker = new AutoAddTracker(mContext, USER);
+        mAutoTracker = createAutoAddTracker(USER);
+        mAutoTracker.initialize();
 
         assertTrue(mAutoTracker.isAdded(SAVER));
 
@@ -116,22 +124,158 @@
 
     @Test
     public void testIndependentUsers() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
         mAutoTracker.setTileAdded(SAVER);
 
-        mAutoTracker = new AutoAddTracker(mContext, USER + 1);
+        mAutoTracker = createAutoAddTracker(USER + 1);
+        mAutoTracker.initialize();
         assertFalse(mAutoTracker.isAdded(SAVER));
     }
 
     @Test
     public void testChangeUser() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
         mAutoTracker.setTileAdded(SAVER);
 
-        mAutoTracker = new AutoAddTracker(mContext, USER + 1);
+        mAutoTracker = createAutoAddTracker(USER + 1);
         mAutoTracker.changeUser(UserHandle.of(USER));
         assertTrue(mAutoTracker.isAdded(SAVER));
     }
+
+    @Test
+    public void testBroadcastReceiverRegistered() {
+        verify(mBroadcastDispatcher).registerReceiver(
+                any(), mIntentFilterArgumentCaptor.capture(), any(), eq(UserHandle.of(USER)));
+
+        assertTrue(
+                mIntentFilterArgumentCaptor.getValue().hasAction(Intent.ACTION_SETTING_RESTORED));
+    }
+
+    @Test
+    public void testBroadcastReceiverChangesWithUser() {
+        mAutoTracker.changeUser(UserHandle.of(USER + 1));
+
+        InOrder inOrder = Mockito.inOrder(mBroadcastDispatcher);
+        inOrder.verify(mBroadcastDispatcher).unregisterReceiver(any());
+        inOrder.verify(mBroadcastDispatcher)
+                .registerReceiver(any(), any(), any(), eq(UserHandle.of(USER + 1)));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesNotRemovedInSource_noAutoAddedInTarget() {
+        verify(mBroadcastDispatcher).registerReceiver(
+                mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,work,internet,cast";
+        Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, don't remove any current tiles
+        verify(mQSHost, never()).removeTiles(any());
+        assertEquals(restoredAutoAddTiles,
+                mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesRemovedInSource_noAutoAddedInTarget() {
+        verify(mBroadcastDispatcher)
+                .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,internet,cast";
+        Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, remove work tile
+        verify(mQSHost).removeTiles(List.of("work"));
+        assertEquals(restoredAutoAddTiles,
+                mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesRemovedInSource_sameAutoAddedinTarget() {
+        verify(mBroadcastDispatcher)
+                .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,internet,cast";
+        Intent restoreTilesIntent =
+                makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "work", restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, remove work tile
+        verify(mQSHost).removeTiles(List.of("work"));
+        assertEquals(restoredAutoAddTiles,
+                mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesRemovedInSource_othersAutoAddedinTarget() {
+        verify(mBroadcastDispatcher)
+                .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,internet,cast";
+        Intent restoreTilesIntent =
+                makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "inversion", restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, remove work tile
+        verify(mQSHost).removeTiles(List.of("work"));
+
+        String setting = mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER);
+        assertEquals(2, setting.split(",").length);
+        assertTrue(setting.contains("work"));
+        assertTrue(setting.contains("inversion"));
+    }
+
+
+    private Intent makeRestoreIntent(
+            String settingName, String previousValue, String restoredValue) {
+        Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED);
+        intent.putExtra(Intent.EXTRA_SETTING_NAME, settingName);
+        intent.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, previousValue);
+        intent.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, restoredValue);
+        return intent;
+    }
+
+    private AutoAddTracker createAutoAddTracker(int user) {
+        // Null handler wil dispatch sync.
+        return new AutoAddTracker(
+                mSecureSettings,
+                mBroadcastDispatcher,
+                mQSHost,
+                mDumpManager,
+                null,
+                mBackgroundExecutor,
+                user
+        );
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 9e97f80..84bc12f6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -18,14 +18,11 @@
 
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.TestCase.assertFalse;
 
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -67,12 +64,12 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -120,7 +117,6 @@
     private UiEventLogger mUiEventLogger;
     @Mock
     private UserTracker mUserTracker;
-    @Mock
     private SecureSettings mSecureSettings;
     @Mock
     private CustomTileStatePersister mCustomTileStatePersister;
@@ -134,14 +130,15 @@
         MockitoAnnotations.initMocks(this);
         mLooper = TestableLooper.get(this);
         mHandler = new Handler(mLooper.getLooper());
+
+        mSecureSettings = new FakeSettings();
+        mSecureSettings.putStringForUser(
+                QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false);
         mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
                 mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
                 mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
                 mSecureSettings, mCustomTileStatePersister);
         setUpTileFactory();
-
-        when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
-                .thenReturn("");
     }
 
     private void setUpTileFactory() {
@@ -364,6 +361,16 @@
                 .removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId()));
     }
 
+    @Test
+    public void testRemoveTiles() {
+        List<String> tiles = List.of("spec1", "spec2", "spec3");
+        mQSTileHost.saveTilesToSettings(tiles);
+
+        mQSTileHost.removeTiles(List.of("spec1", "spec2"));
+
+        assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs);
+    }
+
     private class TestQSTileHost extends QSTileHost {
         TestQSTileHost(Context context, StatusBarIconController iconController,
                 QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
@@ -389,14 +396,11 @@
         @Override
         void saveTilesToSettings(List<String> tileSpecs) {
             super.saveTilesToSettings(tileSpecs);
-
-            ArgumentCaptor<String> specs = ArgumentCaptor.forClass(String.class);
-            verify(mSecureSettings, atLeastOnce()).putStringForUser(eq(QSTileHost.TILES_SETTING),
-                    specs.capture(), isNull(), eq(false), anyInt(), eq(true));
-
             // After tiles are changed, make sure to call onTuningChanged with the new setting if it
             // changed
-            onTuningChanged(TILES_SETTING, specs.getValue());
+            String specs = mSecureSettings.getStringForUser(
+                    QSTileHost.TILES_SETTING, mUserTracker.getUserId());
+            onTuningChanged(TILES_SETTING, specs);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 35360bd..8b7e20e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -36,6 +36,8 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.policy.Clock
+import com.android.systemui.statusbar.policy.VariableDateView
+import com.android.systemui.statusbar.policy.VariableDateViewController
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
@@ -87,8 +89,14 @@
     @Mock
     private lateinit var privacyDialogController: PrivacyDialogController
     @Mock
+    private lateinit var variableDateViewControllerFactory: VariableDateViewController.Factory
+    @Mock
+    private lateinit var variableDateViewController: VariableDateViewController
+    @Mock
     private lateinit var clock: Clock
     @Mock
+    private lateinit var variableDateView: VariableDateView
+    @Mock
     private lateinit var mockView: View
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private lateinit var context: Context
@@ -109,6 +117,8 @@
         stubViews()
         `when`(iconContainer.context).thenReturn(context)
         `when`(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController)
+        `when`(variableDateViewControllerFactory.create(any()))
+                .thenReturn(variableDateViewController)
         `when`(view.resources).thenReturn(mContext.resources)
         `when`(view.isAttachedToWindow).thenReturn(true)
         `when`(view.context).thenReturn(context)
@@ -133,7 +143,8 @@
                 colorExtractor,
                 privacyDialogController,
                 qsExpansionPathInterpolator,
-                featureFlags
+                featureFlags,
+                variableDateViewControllerFactory
         )
     }
 
@@ -274,6 +285,8 @@
         `when`(view.findViewById<StatusIconContainer>(R.id.statusIcons)).thenReturn(iconContainer)
         `when`(view.findViewById<OngoingPrivacyChip>(R.id.privacy_chip)).thenReturn(privacyChip)
         `when`(view.findViewById<Clock>(R.id.clock)).thenReturn(clock)
+        `when`(view.requireViewById<VariableDateView>(R.id.date)).thenReturn(variableDateView)
+        `when`(view.requireViewById<VariableDateView>(R.id.date_clock)).thenReturn(variableDateView)
     }
 
     private fun setPrivacyController(micCamera: Boolean, location: Boolean) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index d44a526..e939411 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -17,6 +17,7 @@
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.assertEquals;
 
+import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
@@ -327,4 +328,77 @@
         assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
         assertTrue(mCastTile.getState().secondaryLabel.toString().startsWith(connected.name));
     }
+
+    @Test
+    public void testExpandView_wifiNotConnected() {
+        mCastTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertFalse(mCastTile.getState().forceExpandIcon);
+    }
+
+    @Test
+    public void testExpandView_wifiEnabledNotCasting() {
+        enableWifiAndProcessMessages();
+
+        assertTrue(mCastTile.getState().forceExpandIcon);
+    }
+
+    @Test
+    public void testExpandView_casting_projection() {
+        CastController.CastDevice device = new CastController.CastDevice();
+        device.state = CastController.CastDevice.STATE_CONNECTED;
+        List<CastDevice> devices = new ArrayList<>();
+        devices.add(device);
+        when(mController.getCastDevices()).thenReturn(devices);
+
+        enableWifiAndProcessMessages();
+
+        assertFalse(mCastTile.getState().forceExpandIcon);
+    }
+
+    @Test
+    public void testExpandView_connecting_projection() {
+        CastController.CastDevice connecting = new CastController.CastDevice();
+        connecting.state = CastDevice.STATE_CONNECTING;
+        connecting.name = "Test Casting Device";
+
+        List<CastDevice> devices = new ArrayList<>();
+        devices.add(connecting);
+        when(mController.getCastDevices()).thenReturn(devices);
+
+        enableWifiAndProcessMessages();
+
+        assertFalse(mCastTile.getState().forceExpandIcon);
+    }
+
+    @Test
+    public void testExpandView_casting_mediaRoute() {
+        CastController.CastDevice device = new CastController.CastDevice();
+        device.state = CastDevice.STATE_CONNECTED;
+        device.tag = mock(MediaRouter.RouteInfo.class);
+        List<CastDevice> devices = new ArrayList<>();
+        devices.add(device);
+        when(mController.getCastDevices()).thenReturn(devices);
+
+        enableWifiAndProcessMessages();
+
+        assertTrue(mCastTile.getState().forceExpandIcon);
+    }
+
+    @Test
+    public void testExpandView_connecting_mediaRoute() {
+        CastController.CastDevice connecting = new CastController.CastDevice();
+        connecting.state = CastDevice.STATE_CONNECTING;
+        connecting.tag = mock(RouteInfo.class);
+        connecting.name = "Test Casting Device";
+
+        List<CastDevice> devices = new ArrayList<>();
+        devices.add(connecting);
+        when(mController.getCastDevices()).thenReturn(devices);
+
+        enableWifiAndProcessMessages();
+
+        assertTrue(mCastTile.getState().forceExpandIcon);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
new file mode 100644
index 0000000..fa5f70c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -0,0 +1,127 @@
+package com.android.systemui.qs.tiles.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.SysuiTestCase;
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class InternetAdapterTest extends SysuiTestCase {
+
+    private static final String WIFI_TITLE = "Wi-Fi Title";
+    private static final String WIFI_SUMMARY = "Wi-Fi Summary";
+
+    @Mock
+    private WifiEntry mInternetWifiEntry;
+    @Mock
+    private List<WifiEntry> mWifiEntries;
+    @Mock
+    private WifiEntry mWifiEntry;
+    @Mock
+    private InternetDialogController mInternetDialogController;
+    @Mock
+    private WifiUtils.InternetIconInjector mWifiIconInjector;
+
+    private InternetAdapter mInternetAdapter;
+    private InternetAdapter.InternetViewHolder mViewHolder;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
+        when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+        when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
+        when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+        when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
+        when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+
+        mInternetAdapter = new InternetAdapter(mInternetDialogController);
+        mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0);
+        mInternetAdapter.setWifiEntries(Arrays.asList(mWifiEntry), 1 /* wifiEntriesCount */);
+        mViewHolder.mWifiIconInjector = mWifiIconInjector;
+    }
+
+    @Test
+    public void getItemCount_returnWifiEntriesCount() {
+        for (int i = 0; i < InternetDialogController.MAX_WIFI_ENTRY_COUNT; i++) {
+            mInternetAdapter.setWifiEntries(mWifiEntries, i /* wifiEntriesCount */);
+
+            assertThat(mInternetAdapter.getItemCount()).isEqualTo(i);
+        }
+    }
+
+    @Test
+    public void onBindViewHolder_bindWithOpenWifiNetwork_verifyView() {
+        when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_NONE);
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onBindViewHolder_bindWithSecurityWifiNetwork_verifyView() {
+        when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_PSK);
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void onBindViewHolder_wifiLevelUnreachable_shouldNotGetWifiIcon() {
+        reset(mWifiIconInjector);
+        when(mWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
+
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        verify(mWifiIconInjector, never()).getIcon(anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void onBindViewHolder_shouldNotShowXLevelIcon_getIconWithInternet() {
+        when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(false);
+
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        verify(mWifiIconInjector).getIcon(eq(false) /* noInternet */, anyInt());
+    }
+
+    @Test
+    public void onBindViewHolder_shouldShowXLevelIcon_getIconWithNoInternet() {
+        when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
+
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        verify(mWifiIconInjector).getIcon(eq(true) /* noInternet */, anyInt());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
new file mode 100644
index 0000000..cacc409
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -0,0 +1,491 @@
+package com.android.systemui.qs.tiles.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class InternetDialogControllerTest extends SysuiTestCase {
+
+    private static final int SUB_ID = 1;
+    private static final String CONNECTED_TITLE = "Connected Wi-Fi Title";
+    private static final String CONNECTED_SUMMARY = "Connected Wi-Fi Summary";
+
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private Handler mHandler;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private GlobalSettings mGlobalSettings;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private NetworkController.AccessPointController mAccessPointController;
+    @Mock
+    private WifiEntry mConnectedEntry;
+    @Mock
+    private WifiEntry mWifiEntry1;
+    @Mock
+    private WifiEntry mWifiEntry2;
+    @Mock
+    private WifiEntry mWifiEntry3;
+    @Mock
+    private WifiEntry mWifiEntry4;
+    @Mock
+    private ServiceState mServiceState;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private WifiUtils.InternetIconInjector mWifiIconInjector;
+    @Mock
+    InternetDialogController.InternetDialogCallback mInternetDialogCallback;
+
+    private MockInternetDialogController mInternetDialogController;
+    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+    private List<WifiEntry> mAccessPoints = new ArrayList<>();
+    private List<WifiEntry> mWifiEntries = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
+        when(mConnectedEntry.hasInternetAccess()).thenReturn(true);
+        when(mWifiEntry1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        when(mWifiEntry2.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        when(mWifiEntry3.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        when(mWifiEntry4.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID});
+
+        mInternetDialogController = new MockInternetDialogController(mContext,
+                mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
+                mSubscriptionManager, mTelephonyManager, mWifiManager,
+                mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
+                mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController);
+        mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
+                mInternetDialogController.mOnSubscriptionsChangedListener);
+        mInternetDialogController.onStart(mInternetDialogCallback, true);
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDialogController.mActivityStarter = mActivityStarter;
+        mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
+    }
+
+    @Test
+    public void getDialogTitleText_withAirplaneModeOn_returnAirplaneMode() {
+        mInternetDialogController.setAirplaneModeEnabled(true);
+
+        assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(),
+                getResourcesString("airplane_mode")));
+    }
+
+    @Test
+    public void getDialogTitleText_withAirplaneModeOff_returnInternet() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+
+        assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(),
+                getResourcesString("quick_settings_internet_label")));
+    }
+
+    @Test
+    public void getSubtitleText_withAirplaneModeOn_returnNull() {
+        mInternetDialogController.setAirplaneModeEnabled(true);
+
+        assertThat(mInternetDialogController.getSubtitleText(false)).isNull();
+    }
+
+    @Test
+    public void getSubtitleText_withWifiOff_returnWifiIsOff() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(false);
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isEqualTo(getResourcesString("wifi_is_off"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isNotEqualTo(getResourcesString("wifi_is_off"));
+    }
+
+    @Test
+    public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        assertThat(mInternetDialogController.getSubtitleText(true))
+                .isEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(true))
+                .isNotEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
+    }
+
+    @Test
+    public void getSubtitleText_withWifiEntry_returnTapToConnect() {
+        // The preconditions WiFi Entries is already in setUp()
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isEqualTo(getResourcesString("tap_a_network_to_connect"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isNotEqualTo(getResourcesString("tap_a_network_to_connect"));
+    }
+
+    @Test
+    public void getSubtitleText_deviceLockedWithWifiOn_returnUnlockToViewNetworks() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
+                getResourcesString("unlock_to_view_networks")));
+    }
+
+    @Test
+    public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
+        doReturn(mServiceState).when(mTelephonyManager).getServiceState();
+        doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState();
+
+        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
+                getResourcesString("all_network_unavailable")));
+    }
+
+    @Test
+    public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
+        doReturn(mServiceState).when(mTelephonyManager).getServiceState();
+
+        when(mTelephonyManager.isDataEnabled()).thenReturn(false);
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isEqualTo(getResourcesString("non_carrier_network_unavailable"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isNotEqualTo(getResourcesString("non_carrier_network_unavailable"));
+    }
+
+    @Test
+    public void getWifiDetailsSettingsIntent_withNoConnectedEntry_returnNull() {
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNull();
+    }
+
+    @Test
+    public void getWifiDetailsSettingsIntent_withNoConnectedEntryKey_returnNull() {
+        when(mConnectedEntry.getKey()).thenReturn(null);
+
+        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNull();
+    }
+
+    @Test
+    public void getWifiDetailsSettingsIntent_withConnectedEntryKey_returnIntent() {
+        when(mConnectedEntry.getKey()).thenReturn("test_key");
+
+        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNotNull();
+    }
+
+    @Test
+    public void getWifiDrawable_withConnectedEntry_returnIntentIconWithCorrectColor() {
+        final Drawable drawable = mock(Drawable.class);
+        when(mWifiIconInjector.getIcon(anyBoolean(), anyInt())).thenReturn(drawable);
+
+        mInternetDialogController.getInternetWifiDrawable(mConnectedEntry);
+
+        verify(mWifiIconInjector).getIcon(eq(false), anyInt());
+        verify(drawable).setTint(mContext.getColor(R.color.connected_network_primary_color));
+    }
+
+    @Test
+    public void launchWifiNetworkDetailsSetting_withNoConnectedEntry_doNothing() {
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        mInternetDialogController.launchWifiNetworkDetailsSetting();
+
+        verify(mActivityStarter, never())
+                .postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
+    }
+
+    @Test
+    public void launchWifiNetworkDetailsSetting_withConnectedEntryKey_startActivity() {
+        when(mConnectedEntry.getKey()).thenReturn("test_key");
+
+        mInternetDialogController.launchWifiNetworkDetailsSetting();
+
+        verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
+    }
+
+    @Test
+    public void isDeviceLocked_keyguardIsUnlocked_returnFalse() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+
+        assertThat(mInternetDialogController.isDeviceLocked()).isFalse();
+    }
+
+    @Test
+    public void isDeviceLocked_keyguardIsLocked_returnTrue() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+        assertThat(mInternetDialogController.isDeviceLocked()).isTrue();
+    }
+
+    @Test
+    public void onAccessPointsChanged_canNotConfigWifi_doNothing() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.mCanConfigWifi = false;
+
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        verify(mInternetDialogCallback, never()).onAccessPointsChanged(any(), any());
+    }
+
+    @Test
+    public void onAccessPointsChanged_nullAccessPoints_callbackBothNull() {
+        reset(mInternetDialogCallback);
+
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        verify(mInternetDialogCallback)
+                .onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntry_callbackConnectedEntryOnly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_noConnectedEntryAndOneOther_callbackWifiEntriesOnly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mWifiEntry1);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        verify(mInternetDialogCallback)
+                .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndOneOther_callbackCorrectly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndTwoOthers_callbackCorrectly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        mAccessPoints.add(mWifiEntry2);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        mWifiEntries.add(mWifiEntry2);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndThreeOthers_callbackCutMore() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        mAccessPoints.add(mWifiEntry2);
+        mAccessPoints.add(mWifiEntry3);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        mWifiEntries.add(mWifiEntry2);
+        mWifiEntries.add(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+
+        // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(false);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.remove(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndFourOthers_callbackCutMore() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        mAccessPoints.add(mWifiEntry2);
+        mAccessPoints.add(mWifiEntry3);
+        mAccessPoints.add(mWifiEntry4);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        mWifiEntries.add(mWifiEntry2);
+        mWifiEntries.add(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+
+        // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(false);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.remove(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    private String getResourcesString(String name) {
+        return mContext.getResources().getString(getResourcesId(name));
+    }
+
+    private int getResourcesId(String name) {
+        return mContext.getResources().getIdentifier(name, "string",
+                mContext.getPackageName());
+    }
+
+    private class MockInternetDialogController extends InternetDialogController {
+
+        private GlobalSettings mGlobalSettings;
+        private boolean mIsAirplaneModeOn;
+
+        MockInternetDialogController(Context context, UiEventLogger uiEventLogger,
+                ActivityStarter starter, AccessPointController accessPointController,
+                SubscriptionManager subscriptionManager, TelephonyManager telephonyManager,
+                @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
+                @Main Handler handler, @Main Executor mainExecutor,
+                BroadcastDispatcher broadcastDispatcher,
+                KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings,
+                KeyguardStateController keyguardStateController) {
+            super(context, uiEventLogger, starter, accessPointController, subscriptionManager,
+                    telephonyManager, wifiManager, connectivityManager, handler, mainExecutor,
+                    broadcastDispatcher, keyguardUpdateMonitor, globalSettings,
+                    keyguardStateController);
+            mGlobalSettings = globalSettings;
+        }
+
+        @Override
+        boolean isAirplaneModeEnabled() {
+            return mIsAirplaneModeOn;
+        }
+
+        public void setAirplaneModeEnabled(boolean enabled) {
+            mIsAirplaneModeOn = enabled;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
new file mode 100644
index 0000000..fa9c053
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -0,0 +1,292 @@
+package com.android.systemui.qs.tiles.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class InternetDialogTest extends SysuiTestCase {
+
+    private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
+    private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary";
+    private static final String WIFI_TITLE = "Connected Wi-Fi Title";
+    private static final String WIFI_SUMMARY = "Connected Wi-Fi Summary";
+
+    @Mock
+    private Handler mHandler;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private WifiEntry mInternetWifiEntry;
+    @Mock
+    private List<WifiEntry> mWifiEntries;
+    @Mock
+    private InternetAdapter mInternetAdapter;
+    @Mock
+    private InternetDialogController mInternetDialogController;
+
+    private InternetDialog mInternetDialog;
+    private View mDialogView;
+    private View mSubTitle;
+    private LinearLayout mMobileDataToggle;
+    private LinearLayout mWifiToggle;
+    private LinearLayout mConnectedWifi;
+    private RecyclerView mWifiList;
+    private LinearLayout mSeeAll;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
+        when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+        when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
+        when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+        when(mWifiEntries.size()).thenReturn(1);
+
+        when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE);
+        when(mInternetDialogController.getMobileNetworkSummary())
+                .thenReturn(MOBILE_NETWORK_SUMMARY);
+        when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager);
+
+        mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
+                mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler);
+        mInternetDialog.mAdapter = mInternetAdapter;
+        mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry);
+        mInternetDialog.show();
+
+        mDialogView = mInternetDialog.mDialogView;
+        mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+        mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout);
+        mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+        mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
+        mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
+        mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
+    }
+
+    @After
+    public void tearDown() {
+        mInternetDialog.dismissDialog();
+    }
+
+    @Test
+    public void hideWifiViews_WifiViewsGone() {
+        mInternetDialog.hideWifiViews();
+
+        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_withApmOn_internetDialogSubTitleGone() {
+        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
+        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateDialog_withApmOn_mobileDataLayoutGone() {
+        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
+        doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/);
+        doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndNoWifiList_hideWifiListAndSeeAll() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndHasWifiList_showWifiListAndSeeAll() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasInternetWifi_showHighlightWifiToggle() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mWifiToggle.getBackground()).isNotNull();
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasInternetWifi_hideConnectedWifi() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasWifiList_hideWifiListAndSeeAll() {
+        // The preconditions WiFi entries are already in setUp()
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() {
+        mSeeAll.performClick();
+
+        verify(mInternetDialogController).launchNetworkSetting();
+    }
+
+    @Test
+    public void showProgressBar_wifiDisabled_hideProgressBar() {
+        Mockito.reset(mHandler);
+        when(mWifiManager.isWifiEnabled()).thenReturn(false);
+
+        mInternetDialog.showProgressBar();
+
+        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
+    }
+
+    @Test
+    public void showProgressBar_deviceLocked_hideProgressBar() {
+        Mockito.reset(mHandler);
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.showProgressBar();
+
+        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
+    }
+
+    @Test
+    public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
+        Mockito.reset(mHandler);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+
+        mInternetDialog.showProgressBar();
+
+        // Show progress bar
+        assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+
+        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mHandler).postDelayed(runnableCaptor.capture(),
+                eq(InternetDialog.PROGRESS_DELAY_MS));
+        runnableCaptor.getValue().run();
+
+        // Then hide progress bar
+        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+    }
+
+    @Test
+    public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
+        Mockito.reset(mHandler);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry*/);
+
+        mInternetDialog.showProgressBar();
+
+        // Show progress bar
+        assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+
+        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mHandler).postDelayed(runnableCaptor.capture(),
+                eq(InternetDialog.PROGRESS_DELAY_MS));
+        runnableCaptor.getValue().run();
+
+        // Then hide searching sub-title only
+        assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+        assertThat(mInternetDialog.mIsSearchingHidden).isTrue();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
index 10c878a..6f081c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
@@ -34,6 +34,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
 
@@ -274,7 +275,8 @@
             when(client.start(/* response */ any(), /* maxPages */ anyFloat()))
                     .thenReturn(immediateFuture(session));
             return new ScrollCaptureController(context, context.getMainExecutor(),
-                    client, new ImageTileSet(context.getMainThreadHandler()));
+                    client, new ImageTileSet(context.getMainThreadHandler()),
+                    new UiEventLoggerFake());
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index f5ce673..4c90063 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -111,6 +111,7 @@
     private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
             "bar");
 
+    private String mKeyguardTryFingerprintMsg;
     private String mDisclosureWithOrganization;
     private String mDisclosureGeneric;
     private String mFinancedDisclosureWithOrganization;
@@ -182,6 +183,7 @@
         mContext.addMockSystemService(UserManager.class, mUserManager);
         mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
         mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
+        mKeyguardTryFingerprintMsg = mContext.getString(R.string.keyguard_try_fingerprint);
         mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
                 ORGANIZATION_NAME);
         mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
@@ -677,6 +679,34 @@
         verifyTransientMessage(message);
     }
 
+    @Test
+    public void faceAuthMessageSuppressed() {
+        createController();
+        String faceHelpMsg = "Face auth help message";
+
+        // GIVEN state of showing message when keyguard screen is on
+        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
+
+        // GIVEN fingerprint is also running (not udfps)
+        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isUdfpsAvailable()).thenReturn(false);
+
+        mController.setVisible(true);
+
+        // WHEN a face help message comes in
+        mController.getKeyguardCallback().onBiometricHelp(
+                KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, faceHelpMsg,
+                BiometricSourceType.FACE);
+
+        // THEN "try fingerprint" message appears (and not the face help message)
+        verifyTransientMessage(mKeyguardTryFingerprintMsg);
+
+        // THEN the face help message is still announced for a11y
+        verify(mIndicationAreaBottom).announceForAccessibility(eq(faceHelpMsg));
+    }
+
     private void sendUpdateDisclosureBroadcast() {
         mBroadcastReceiver.onReceive(mContext, new Intent());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
new file mode 100644
index 0000000..97fe25d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.function.Consumer
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LightRevealScrimTest : SysuiTestCase() {
+
+  private lateinit var scrim: LightRevealScrim
+  private var isOpaque = false
+
+  @Before
+  fun setUp() {
+    scrim = LightRevealScrim(context, null)
+    scrim.isScrimOpaqueChangedListener = Consumer { opaque ->
+      isOpaque = opaque
+    }
+    scrim.revealAmount = 0f
+    assertTrue("Scrim is not opaque in initial setup", scrim.isScrimOpaque)
+  }
+
+  @Test
+  fun testAlphaSetsOpaque() {
+    scrim.alpha = 0.5f
+    assertFalse("Scrim is opaque even though alpha is set", scrim.isScrimOpaque)
+  }
+
+  @Test
+  fun testVisibilitySetsOpaque() {
+    scrim.visibility = View.INVISIBLE
+    assertFalse("Scrim is opaque even though it's invisible", scrim.isScrimOpaque)
+    scrim.visibility = View.GONE
+    assertFalse("Scrim is opaque even though it's gone", scrim.isScrimOpaque)
+  }
+
+  @Test
+  fun testRevealSetsOpaque() {
+    scrim.revealAmount = 0.5f
+    assertFalse("Scrim is opaque even though it's revealed", scrim.isScrimOpaque)
+  }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index ddd7854..90b8a74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -146,7 +146,7 @@
         mNotificationShadeWindowController.attach();
 
         clearInvocations(mWindowManager);
-        mNotificationShadeWindowController.setLightRevealScrimAmount(0f);
+        mNotificationShadeWindowController.setLightRevealScrimOpaque(true);
         verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
         assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) == 0).isTrue();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 6c1a3c9..bcc257d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -16,6 +16,11 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -55,6 +60,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -91,6 +98,10 @@
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
 
+    @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
+            mInteractionEventHandlerCaptor;
+    private NotificationShadeWindowView.InteractionEventHandler mInteractionEventHandler;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -147,4 +158,49 @@
         verify(mDragDownHelper).onTouchEvent(ev);
         ev.recycle();
     }
+
+    @Test
+    public void testInterceptTouchWhenShowingAltAuth() {
+        captureInteractionEventHandler();
+
+        // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true);
+        when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
+
+        // THEN we should intercept touch
+        assertTrue(mInteractionEventHandler.shouldInterceptTouchEvent(mock(MotionEvent.class)));
+    }
+
+    @Test
+    public void testNoInterceptTouch() {
+        captureInteractionEventHandler();
+
+        // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(false);
+        when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
+
+        // THEN we shouldn't intercept touch
+        assertFalse(mInteractionEventHandler.shouldInterceptTouchEvent(mock(MotionEvent.class)));
+    }
+
+    @Test
+    public void testHandleTouchEventWhenShowingAltAuth() {
+        captureInteractionEventHandler();
+
+        // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true);
+        when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
+
+        // THEN we should handle the touch
+        assertTrue(mInteractionEventHandler.handleTouchEvent(mock(MotionEvent.class)));
+    }
+
+    private void captureInteractionEventHandler() {
+        verify(mView).setInteractionEventHandler(mInteractionEventHandlerCaptor.capture());
+        mInteractionEventHandler = mInteractionEventHandlerCaptor.getValue();
+
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 6de5866..f3420be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -624,7 +624,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
-                mScrimBehind, false,
+                mScrimBehind, true,
                 mScrimForBubble, true
         ));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 57198db..4a5770d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -238,7 +238,7 @@
         mNetworkController.setNoNetworksAvailable(false);
         setWifiStateForVcn(true, testSsid);
         setWifiLevelForVcn(0);
-        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
+        verifyLastMobileDataIndicatorsForVcn(true, 0, TelephonyIcons.ICON_CWF, false);
 
         mNetworkController.setNoNetworksAvailable(true);
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
@@ -246,11 +246,11 @@
 
             setConnectivityViaCallbackInNetworkControllerForVcn(
                     NetworkCapabilities.TRANSPORT_CELLULAR, true, true, mVcnTransportInfo);
-            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
+            verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, true);
 
             setConnectivityViaCallbackInNetworkControllerForVcn(
                     NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo);
-            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
+            verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
new file mode 100644
index 0000000..871a48c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.Date
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class VariableDateViewControllerTest : SysuiTestCase() {
+
+    companion object {
+        private const val TIME_STAMP = 1_500_000_000_000
+        private const val LONG_PATTERN = "EEEMMMd"
+        private const val SHORT_PATTERN = "MMMd"
+        private const val CHAR_WIDTH = 10f
+    }
+
+    @Mock
+    private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock
+    private lateinit var view: VariableDateView
+    @Captor
+    private lateinit var onMeasureListenerCaptor: ArgumentCaptor<VariableDateView.OnMeasureListener>
+
+    private var lastText: String? = null
+
+    private lateinit var systemClock: FakeSystemClock
+    private lateinit var testableLooper: TestableLooper
+    private lateinit var testableHandler: Handler
+    private lateinit var controller: VariableDateViewController
+
+    private lateinit var longText: String
+    private lateinit var shortText: String
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
+        testableHandler = Handler(testableLooper.looper)
+
+        systemClock = FakeSystemClock()
+        systemClock.setCurrentTimeMillis(TIME_STAMP)
+
+        `when`(view.longerPattern).thenReturn(LONG_PATTERN)
+        `when`(view.shorterPattern).thenReturn(SHORT_PATTERN)
+        `when`(view.handler).thenReturn(testableHandler)
+
+        `when`(view.setText(anyString())).thenAnswer {
+            lastText = it.arguments[0] as? String
+            Unit
+        }
+        `when`(view.isAttachedToWindow).thenReturn(true)
+
+        val date = Date(TIME_STAMP)
+        longText = getTextForFormat(date, getFormatFromPattern(LONG_PATTERN))
+        shortText = getTextForFormat(date, getFormatFromPattern(SHORT_PATTERN))
+
+        // Assume some sizes for the text, the controller doesn't need to know if these sizes are
+        // the true ones
+        `when`(view.getDesiredWidthForText(any())).thenAnswer {
+            getTextLength(it.arguments[0] as CharSequence)
+        }
+
+        controller = VariableDateViewController(
+                systemClock,
+                broadcastDispatcher,
+                testableHandler,
+                view
+        )
+
+        controller.init()
+        testableLooper.processAllMessages()
+
+        verify(view).onAttach(capture(onMeasureListenerCaptor))
+    }
+
+    @Test
+    fun testViewStartsWithLongText() {
+        assertThat(lastText).isEqualTo(longText)
+    }
+
+    @Test
+    fun testListenerNotNull() {
+        assertThat(onMeasureListenerCaptor.value).isNotNull()
+    }
+
+    @Test
+    fun testLotsOfSpaceUseLongText() {
+        onMeasureListenerCaptor.value.onMeasureAction(10000)
+
+        testableLooper.processAllMessages()
+        assertThat(lastText).isEqualTo(longText)
+    }
+
+    @Test
+    fun testSmallSpaceUseEmpty() {
+        onMeasureListenerCaptor.value.onMeasureAction(1)
+        testableLooper.processAllMessages()
+
+        assertThat(lastText).isEmpty()
+    }
+
+    @Test
+    fun testSpaceInBetweenUseShortText() {
+        val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt()
+
+        onMeasureListenerCaptor.value.onMeasureAction(average)
+        testableLooper.processAllMessages()
+
+        assertThat(lastText).isEqualTo(shortText)
+    }
+
+    @Test
+    fun testSwitchBackToLonger() {
+        onMeasureListenerCaptor.value.onMeasureAction(1)
+        testableLooper.processAllMessages()
+
+        onMeasureListenerCaptor.value.onMeasureAction(10000)
+        testableLooper.processAllMessages()
+
+        assertThat(lastText).isEqualTo(longText)
+    }
+
+    @Test
+    fun testNoSwitchingWhenFrozen() {
+        `when`(view.freezeSwitching).thenReturn(true)
+
+        val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt()
+        onMeasureListenerCaptor.value.onMeasureAction(average)
+        testableLooper.processAllMessages()
+        assertThat(lastText).isEqualTo(longText)
+
+        onMeasureListenerCaptor.value.onMeasureAction(1)
+        testableLooper.processAllMessages()
+        assertThat(lastText).isEqualTo(longText)
+    }
+
+    private fun getTextLength(text: CharSequence): Float {
+        return text.length * CHAR_WIDTH
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
new file mode 100644
index 0000000..eebcbe6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.usb
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.hardware.usb.IUsbSerialReader
+import android.hardware.usb.UsbAccessory
+import android.hardware.usb.UsbManager
+import android.testing.AndroidTestingRunner
+import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.lang.Exception
+
+/**
+ * UsbPermissionActivityTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class UsbPermissionActivityTest : SysuiTestCase() {
+
+    class UsbPermissionActivityTestable : UsbPermissionActivity()
+
+    @Rule
+    @JvmField
+    var activityRule = ActivityTestRule<UsbPermissionActivityTestable>(
+            UsbPermissionActivityTestable::class.java, false, false)
+
+    private val activityIntent = Intent(mContext, UsbPermissionActivityTestable::class.java)
+            .apply {
+                flags = Intent.FLAG_ACTIVITY_NEW_TASK
+                putExtra(UsbManager.EXTRA_PACKAGE, "com.android.systemui")
+                putExtra(Intent.EXTRA_INTENT, PendingIntent.getBroadcast(
+                        mContext,
+                        334,
+                        Intent("NO_ACTION"),
+                        PendingIntent.FLAG_MUTABLE))
+                putExtra(UsbManager.EXTRA_ACCESSORY, UsbAccessory(
+                        "manufacturer",
+                        "model",
+                        "description",
+                        "version",
+                        "uri",
+                        object : IUsbSerialReader.Stub() {
+                            override fun getSerial(packageName: String): String {
+                                return "serial"
+                            }
+                        }))
+            }
+
+    @Before
+    fun setUp() {
+        activityRule.launchActivity(activityIntent)
+    }
+
+    @After
+    fun tearDown() {
+        activityRule.finishActivity()
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun testHideNonSystemOverlay() {
+        assertThat(activityRule.activity.window.attributes.privateFlags and
+                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+                .isEqualTo(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
index a34c598..0e9d96c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.util.sensors;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -338,30 +340,25 @@
     @Test
     public void testSecondaryCancelsSecondary() {
         TestableListener listener = new TestableListener();
-        ThresholdSensor.Listener cancelingListener = new ThresholdSensor.Listener() {
-            @Override
-            public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent event) {
-                mProximitySensor.pause();
-            }
-        };
+        ThresholdSensor.Listener cancelingListener = event -> mProximitySensor.pause();
 
         mProximitySensor.register(listener);
         mProximitySensor.register(cancelingListener);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
 
         mThresholdSensorPrimary.triggerEvent(true, 0);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
         mThresholdSensorSecondary.triggerEvent(true, 0);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isTrue();
+        assertThat(listener.mCallCount).isEqualTo(1);
 
         // The proximity sensor should now be canceled. Advancing the clock should do nothing.
-        assertEquals(0, mFakeExecutor.numPending());
+        assertThat(mFakeExecutor.numPending()).isEqualTo(0);
         mThresholdSensorSecondary.triggerEvent(false, 1);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isTrue();
+        assertThat(listener.mCallCount).isEqualTo(1);
 
         mProximitySensor.unregister(listener);
     }
@@ -372,33 +369,66 @@
 
         TestableListener listener = new TestableListener();
 
-        // WE immediately register the secondary sensor.
+        // We immediately register the secondary sensor.
         mProximitySensor.register(listener);
-        assertFalse(mThresholdSensorPrimary.isPaused());
-        assertFalse(mThresholdSensorSecondary.isPaused());
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(mThresholdSensorPrimary.isPaused()).isTrue();
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
 
         mThresholdSensorPrimary.triggerEvent(true, 0);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
         mThresholdSensorSecondary.triggerEvent(true, 0);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isTrue();
+        assertThat(listener.mCallCount).isEqualTo(1);
 
         // The secondary sensor should now remain resumed indefinitely.
-        assertFalse(mThresholdSensorSecondary.isPaused());
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
         mThresholdSensorSecondary.triggerEvent(false, 1);
-        assertFalse(listener.mLastEvent.getBelow());
-        assertEquals(2, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isFalse();
+        assertThat(listener.mCallCount).isEqualTo(2);
 
         // The secondary is still running, and not polling with the executor.
-        assertFalse(mThresholdSensorSecondary.isPaused());
-        assertEquals(0, mFakeExecutor.numPending());
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+        assertThat(mFakeExecutor.numPending()).isEqualTo(0);
 
         mProximitySensor.unregister(listener);
     }
 
+    @Test
+    public void testSecondaryPausesPrimary() {
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isFalse();
+        assertThat(mThresholdSensorSecondary.isPaused()).isTrue();
+
+        mProximitySensor.setSecondarySafe(true);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isTrue();
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+    }
+
+    @Test
+    public void testSecondaryResumesPrimary() {
+        mProximitySensor.setSecondarySafe(true);
+
+        TestableListener listener = new TestableListener();
+        mProximitySensor.register(listener);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isTrue();
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+
+        mProximitySensor.setSecondarySafe(false);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isFalse();
+        assertThat(mThresholdSensorSecondary.isPaused()).isTrue();
+
+
+    }
+
     private static class TestableListener implements ThresholdSensor.Listener {
         ThresholdSensor.ThresholdSensorEvent mLastEvent;
         int mCallCount = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
index 6976422..7bb2674 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
@@ -31,6 +31,7 @@
     private final Map<SettingsKey, String> mValues = new HashMap<>();
     private final Map<SettingsKey, List<ContentObserver>> mContentObservers =
             new HashMap<>();
+    private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
 
     public static final Uri CONTENT_URI = Uri.parse("content://settings/fake");
 
@@ -55,9 +56,15 @@
     @Override
     public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
             ContentObserver settingsObserver, int userHandle) {
-        SettingsKey key = new SettingsKey(userHandle, uri.toString());
-        mContentObservers.putIfAbsent(key, new ArrayList<>());
-        List<ContentObserver> observers = mContentObservers.get(key);
+        List<ContentObserver> observers;
+        if (userHandle == UserHandle.USER_ALL) {
+            mContentObserversAllUsers.putIfAbsent(uri.toString(), new ArrayList<>());
+            observers = mContentObserversAllUsers.get(uri.toString());
+        } else {
+            SettingsKey key = new SettingsKey(userHandle, uri.toString());
+            mContentObservers.putIfAbsent(key, new ArrayList<>());
+            observers = mContentObservers.get(key);
+        }
         observers.add(settingsObserver);
     }
 
@@ -67,6 +74,10 @@
             List<ContentObserver> observers = mContentObservers.get(key);
             observers.remove(settingsObserver);
         }
+        for (String key : mContentObserversAllUsers.keySet()) {
+            List<ContentObserver> observers = mContentObserversAllUsers.get(key);
+            observers.remove(settingsObserver);
+        }
     }
 
     @Override
@@ -114,6 +125,10 @@
         for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) {
             observer.dispatchChange(false, List.of(uri), userHandle);
         }
+        for (ContentObserver observer :
+                mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) {
+            observer.dispatchChange(false, List.of(uri), userHandle);
+        }
         return true;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
index 0d560f2..34cae58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.database.ContentObserver;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 
@@ -89,6 +90,16 @@
     }
 
     @Test
+    public void testRegisterContentObserverAllUsers() {
+        mFakeSettings.registerContentObserverForUser(
+                mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+
+        mFakeSettings.putString("cat", "hat");
+
+        verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt());
+    }
+
+    @Test
     public void testUnregisterContentObserver() {
         mFakeSettings.registerContentObserver("cat", mContentObserver);
         mFakeSettings.unregisterContentObserver(mContentObserver);
@@ -98,4 +109,16 @@
         verify(mContentObserver, never()).dispatchChange(
                 anyBoolean(), any(Collection.class), anyInt());
     }
+
+    @Test
+    public void testUnregisterContentObserverAllUsers() {
+        mFakeSettings.registerContentObserverForUser(
+                mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+        mFakeSettings.unregisterContentObserver(mContentObserver);
+
+        mFakeSettings.putString("cat", "hat");
+
+        verify(mContentObserver, never()).dispatchChange(
+                anyBoolean(), any(Collection.class), anyInt());
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 8961a5a..5ecdfe4 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1719,11 +1719,10 @@
         if (client == null) {
             return;
         }
-        Log.w(TAG, "Speaker client died");
-        if (removeCommunicationRouteClient(client.getBinder(), false)
-                != null) {
-            onUpdateCommunicationRoute("onCommunicationRouteClientDied");
-        }
+        Log.w(TAG, "Communication client died");
+        setCommunicationRouteForClient(
+                client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED,
+                "onCommunicationRouteClientDied");
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index afd1889..c220043 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -192,7 +192,9 @@
 
     private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
-    private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.1f;
+    // This value needs to be in sync with the threshold
+    // in RefreshRateConfigs::getFrameRateDivider.
+    private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.0009f;
 
     private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
     private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
@@ -812,7 +814,7 @@
 
         // Override the refresh rate only if it is a divider of the current
         // refresh rate. This calculation needs to be in sync with the native code
-        // in RefreshRateConfigs::getRefreshRateDividerForUid
+        // in RefreshRateConfigs::getFrameRateDivider
         Display.Mode currentMode = info.getMode();
         float numPeriods = currentMode.getRefreshRate() / frameRateHz;
         float numPeriodsRound = Math.round(numPeriods);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b54e8f9..207baf5 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4363,8 +4363,7 @@
                             final int userId = r.getSbn().getUserId();
                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
                                     !mUserProfiles.isCurrentProfile(userId)) {
-                                throw new SecurityException("Disallowed call from listener: "
-                                        + info.service);
+                                continue;
                             }
                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
                                     r.getSbn().getPackageName(), r.getSbn().getTag(),
@@ -4431,8 +4430,7 @@
                         final int userId = r.getSbn().getUserId();
                         if (userId != info.userid && userId != UserHandle.USER_ALL
                                 && !mUserProfiles.isCurrentProfile(userId)) {
-                            throw new SecurityException("Disallowed call from listener: "
-                                    + info.service);
+                            continue;
                         }
                         seen.add(r);
                         if (!r.isSeen()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c477546..140098d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7220,6 +7220,7 @@
             t.traceEnd();
 
             mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
+            mPermissionManager.readLegacyPermissionStateTEMP();
 
             if (!mOnlyCore && mFirstBoot) {
                 requestCopyPreoptedFiles(mInjector);
@@ -7635,7 +7636,6 @@
                     + ((SystemClock.uptimeMillis()-startTime)/1000f)
                     + " seconds");
 
-            mPermissionManager.readLegacyPermissionStateTEMP();
             // If the build fingerprint has changed since the last time we booted,
             // we need to re-grant app permission to catch any new ones that
             // appear.  This is really a hack, and means that apps can in some
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e408822..b6ca67d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -484,6 +484,7 @@
     int mLidNavigationAccessibility;
     int mShortPressOnPowerBehavior;
     int mLongPressOnPowerBehavior;
+    long mLongPressOnPowerAssistantTimeoutMs;
     int mVeryLongPressOnPowerBehavior;
     int mDoublePressOnPowerBehavior;
     int mTriplePressOnPowerBehavior;
@@ -732,6 +733,9 @@
                     Settings.Global.POWER_BUTTON_LONG_PRESS), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POWER_BUTTON_VERY_LONG_PRESS), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
@@ -1732,6 +1736,8 @@
                 com.android.internal.R.integer.config_shortPressOnPowerBehavior);
         mLongPressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_longPressOnPowerBehavior);
+        mLongPressOnPowerAssistantTimeoutMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_longPressOnPowerDurationMs);
         mVeryLongPressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_veryLongPressOnPowerBehavior);
         mDoublePressOnPowerBehavior = mContext.getResources().getInteger(
@@ -1955,7 +1961,7 @@
      */
     private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
         PowerKeyRule(int gestures) {
-            super(KEYCODE_POWER, gestures);
+            super(mContext, KEYCODE_POWER, gestures);
         }
 
         @Override
@@ -1970,6 +1976,15 @@
         }
 
         @Override
+        long getLongPressTimeoutMs() {
+            if (getResolvedLongPressOnPowerBehavior() == LONG_PRESS_POWER_ASSISTANT) {
+                return mLongPressOnPowerAssistantTimeoutMs;
+            } else {
+                return super.getLongPressTimeoutMs();
+            }
+        }
+
+        @Override
         void onLongPress(long eventTime) {
             if (mSingleKeyGestureDetector.beganFromNonInteractive()
                     && !mSupportLongPressPowerWhenNonInteractive) {
@@ -1997,7 +2012,7 @@
      */
     private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
         BackKeyRule(int gestures) {
-            super(KEYCODE_BACK, gestures);
+            super(mContext, KEYCODE_BACK, gestures);
         }
 
         @Override
@@ -2017,7 +2032,7 @@
     }
 
     private void initSingleKeyGestureRules() {
-        mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext);
+        mSingleKeyGestureDetector = new SingleKeyGestureDetector();
 
         int powerKeyGestures = 0;
         if (hasVeryLongPressOnPowerBehavior()) {
@@ -2115,6 +2130,11 @@
                     Settings.Global.POWER_BUTTON_LONG_PRESS,
                     mContext.getResources().getInteger(
                             com.android.internal.R.integer.config_longPressOnPowerBehavior));
+            mLongPressOnPowerAssistantTimeoutMs = Settings.Global.getLong(
+                    mContext.getContentResolver(),
+                    Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS,
+                    mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_longPressOnPowerDurationMs));
             mVeryLongPressOnPowerBehavior = Settings.Global.getInt(resolver,
                     Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
                     mContext.getResources().getInteger(
@@ -5329,6 +5349,9 @@
                 pw.print("mLongPressOnPowerBehavior=");
                 pw.println(longPressOnPowerBehaviorToString(mLongPressOnPowerBehavior));
         pw.print(prefix);
+        pw.print("mLongPressOnPowerAssistantTimeoutMs=");
+        pw.println(mLongPressOnPowerAssistantTimeoutMs);
+        pw.print(prefix);
                 pw.print("mVeryLongPressOnPowerBehavior=");
                 pw.println(veryLongPressOnPowerBehaviorToString(mVeryLongPressOnPowerBehavior));
         pw.print(prefix);
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index 1ef2bf9..6fee69b 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -44,9 +44,6 @@
     private static final int MSG_KEY_VERY_LONG_PRESS = 1;
     private static final int MSG_KEY_DELAYED_PRESS = 2;
 
-    private final long mLongPressTimeout;
-    private final long mVeryLongPressTimeout;
-
     private volatile int mKeyPressCounter;
     private boolean mBeganFromNonInteractive = false;
 
@@ -86,12 +83,19 @@
      *  </pre>
      */
     abstract static class SingleKeyRule {
+
         private final int mKeyCode;
         private final int mSupportedGestures;
+        private final long mDefaultLongPressTimeout;
+        private final long mDefaultVeryLongPressTimeout;
 
-        SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) {
+        SingleKeyRule(Context context, int keyCode, @KeyGestureFlag int supportedGestures) {
             mKeyCode = keyCode;
             mSupportedGestures = supportedGestures;
+            mDefaultLongPressTimeout =
+                ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
+            mDefaultVeryLongPressTimeout = context.getResources().getInteger(
+                com.android.internal.R.integer.config_veryLongPressTimeout);
         }
 
         /**
@@ -134,10 +138,28 @@
          */
         void onMultiPress(long downTime, int count) {}
         /**
+         *  Returns the timeout in milliseconds for a long press.
+         *
+         *  If multipress is also supported, this should always be greater than the multipress
+         *  timeout. If very long press is supported, this should always be less than the very long
+         *  press timeout.
+         */
+        long getLongPressTimeoutMs() {
+            return mDefaultLongPressTimeout;
+        }
+        /**
          *  Callback when long press has been detected.
          */
         void onLongPress(long eventTime) {}
         /**
+         *  Returns the timeout in milliseconds for a very long press.
+         *
+         *  If long press is supported, this should always be longer than the long press timeout.
+         */
+        long getVeryLongPressTimeoutMs() {
+            return mDefaultVeryLongPressTimeout;
+        }
+        /**
          *  Callback when very long press has been detected.
          */
         void onVeryLongPress(long eventTime) {}
@@ -151,10 +173,7 @@
         }
     }
 
-    public SingleKeyGestureDetector(Context context) {
-        mLongPressTimeout = ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
-        mVeryLongPressTimeout = context.getResources().getInteger(
-                com.android.internal.R.integer.config_veryLongPressTimeout);
+    public SingleKeyGestureDetector() {
         mHandler = new KeyHandler();
     }
 
@@ -225,14 +244,14 @@
                 final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0,
                         eventTime);
                 msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, mLongPressTimeout);
+                mHandler.sendMessageDelayed(msg, mActiveRule.getLongPressTimeoutMs());
             }
 
             if (mActiveRule.supportVeryLongPress()) {
                 final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0,
                         eventTime);
                 msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, mVeryLongPressTimeout);
+                mHandler.sendMessageDelayed(msg, mActiveRule.getVeryLongPressTimeoutMs());
             }
         } else {
             mHandler.removeMessages(MSG_KEY_LONG_PRESS);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 7555a7f..c91d8de 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -96,6 +96,7 @@
     private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4;
     private static final int MSG_PROFILE_TIMED_OUT = 5;
     private static final int MSG_WIRED_CHARGING_STARTED = 6;
+    private static final int MSG_SCREEN_POLICY = 7;
 
     private static final long[] CHARGING_VIBRATION_TIME = {
             40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms
@@ -120,6 +121,7 @@
     private final SuspendBlocker mSuspendBlocker;
     private final WindowManagerPolicy mPolicy;
     private final FaceDownDetector mFaceDownDetector;
+    private final ScreenUndimDetector mScreenUndimDetector;
     private final ActivityManagerInternal mActivityManagerInternal;
     private final InputManagerInternal mInputManagerInternal;
     private final InputMethodManagerInternal mInputMethodManagerInternal;
@@ -167,13 +169,14 @@
 
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
             SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-            FaceDownDetector faceDownDetector) {
+            FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
         mContext = context;
         mBatteryStats = batteryStats;
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mSuspendBlocker = suspendBlocker;
         mPolicy = policy;
         mFaceDownDetector = faceDownDetector;
+        mScreenUndimDetector = screenUndimDetector;
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
@@ -620,6 +623,22 @@
     }
 
     /**
+     * Called when the screen policy changes.
+     */
+    public void onScreenPolicyUpdate(int newPolicy) {
+        if (DEBUG) {
+            Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy);
+        }
+
+        synchronized (mLock) {
+            Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY);
+            msg.arg1 = newPolicy;
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    /**
      * Dumps data for bugreports.
      *
      * @param pw The stream to print to.
@@ -659,6 +678,7 @@
         tm.notifyUserActivity();
         mPolicy.userActivity();
         mFaceDownDetector.userActivity(event);
+        mScreenUndimDetector.userActivity();
     }
 
     void postEnhancedDischargePredictionBroadcast(long delayMs) {
@@ -812,6 +832,10 @@
         mSuspendBlocker.release();
     }
 
+    private void screenPolicyChanging(int screenPolicy) {
+        mScreenUndimDetector.recordScreenPolicy(screenPolicy);
+    }
+
     private void lockProfile(@UserIdInt int userId) {
         mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
     }
@@ -852,6 +876,9 @@
                 case MSG_WIRED_CHARGING_STARTED:
                     showWiredChargingStarted(msg.arg1);
                     break;
+                case MSG_SCREEN_POLICY:
+                    screenPolicyChanging(msg.arg1);
+                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3d47dcf..688a3b2 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -274,6 +274,7 @@
     private final BatterySavingStats mBatterySavingStats;
     private final AttentionDetector mAttentionDetector;
     private final FaceDownDetector mFaceDownDetector;
+    private final ScreenUndimDetector mScreenUndimDetector;
     private final BinderService mBinderService;
     private final LocalService mLocalService;
     private final NativeWrapper mNativeWrapper;
@@ -837,9 +838,10 @@
     static class Injector {
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                FaceDownDetector faceDownDetector) {
+                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
             return new Notifier(
-                    looper, context, batteryStats, suspendBlocker, policy, faceDownDetector);
+                    looper, context, batteryStats, suspendBlocker, policy, faceDownDetector,
+                    screenUndimDetector);
         }
 
         SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
@@ -960,6 +962,7 @@
                 mInjector.createAmbientDisplaySuppressionController(context);
         mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
         mFaceDownDetector = new FaceDownDetector(this::onFlip);
+        mScreenUndimDetector = new ScreenUndimDetector();
 
         mBatterySavingStats = new BatterySavingStats(mLock);
         mBatterySaverPolicy =
@@ -1146,7 +1149,7 @@
             mBatteryStats = BatteryStatsService.getService();
             mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
                     mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
-                    mPolicy, mFaceDownDetector);
+                    mPolicy, mFaceDownDetector, mScreenUndimDetector);
 
             mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager,
                     mInjector.createSuspendBlocker(
@@ -1181,6 +1184,7 @@
         mBatterySaverController.systemReady();
         mBatterySaverPolicy.systemReady();
         mFaceDownDetector.systemReady(mContext);
+        mScreenUndimDetector.systemReady(mContext);
 
         // Register for settings changes.
         resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -3190,6 +3194,7 @@
 
                 final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
                         displayPowerRequest, mRequestWaitForNegativeProximity);
+                mNotifier.onScreenPolicyUpdate(displayPowerRequest.policy);
 
                 if (DEBUG_SPEW) {
                     Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
diff --git a/services/core/java/com/android/server/power/ScreenUndimDetector.java b/services/core/java/com/android/server/power/ScreenUndimDetector.java
new file mode 100644
index 0000000..951bc1f
--- /dev/null
+++ b/services/core/java/com/android/server/power/ScreenUndimDetector.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Detects when user manually undims the screen (x times) and acquires a wakelock to keep the screen
+ * on temporarily (without changing the screen timeout setting).
+ */
+public class ScreenUndimDetector {
+    private static final String TAG = "ScreenUndimDetector";
+    private static final boolean DEBUG = false;
+
+    private static final String UNDIM_DETECTOR_WAKE_LOCK = "UndimDetectorWakeLock";
+
+    /** DeviceConfig flag: is keep screen on feature enabled. */
+    static final String KEY_KEEP_SCREEN_ON_ENABLED = "keep_screen_on_enabled";
+    private static final boolean DEFAULT_KEEP_SCREEN_ON_ENABLED = true;
+    private static final int OUTCOME_POWER_BUTTON =
+            FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__POWER_BUTTON;
+    private static final int OUTCOME_TIMEOUT =
+            FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__TIMEOUT;
+    private boolean mKeepScreenOnEnabled;
+
+    /** DeviceConfig flag: how long should we keep the screen on. */
+    @VisibleForTesting
+    static final String KEY_KEEP_SCREEN_ON_FOR_MILLIS = "keep_screen_on_for_millis";
+    @VisibleForTesting
+    static final long DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS = TimeUnit.MINUTES.toMillis(10);
+    private long mKeepScreenOnForMillis;
+
+    /** DeviceConfig flag: how many user undims required to trigger keeping the screen on. */
+    @VisibleForTesting
+    static final String KEY_UNDIMS_REQUIRED = "undims_required";
+    @VisibleForTesting
+    static final int DEFAULT_UNDIMS_REQUIRED = 2;
+    private int mUndimsRequired;
+
+    /**
+     * DeviceConfig flag: what is the maximum duration between undims to still consider them
+     * consecutive.
+     */
+    @VisibleForTesting
+    static final String KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS =
+            "max_duration_between_undims_millis";
+    @VisibleForTesting
+    static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = TimeUnit.MINUTES.toMillis(5);
+    private long mMaxDurationBetweenUndimsMillis;
+
+    @VisibleForTesting
+    PowerManager.WakeLock mWakeLock;
+
+    @VisibleForTesting
+    int mCurrentScreenPolicy;
+    @VisibleForTesting
+    int mUndimCounter = 0;
+    @VisibleForTesting
+    long mUndimCounterStartedMillis;
+    private long mUndimOccurredTime = -1;
+    private long mInteractionAfterUndimTime = -1;
+    private InternalClock mClock;
+
+    public ScreenUndimDetector() {
+        mClock = new InternalClock();
+    }
+
+    ScreenUndimDetector(InternalClock clock) {
+        mClock = clock;
+    }
+
+    static class InternalClock {
+        public long getCurrentTime() {
+            return SystemClock.elapsedRealtime();
+        }
+    }
+
+    /** Should be called in parent's systemReady() */
+    public void systemReady(Context context) {
+        readValuesFromDeviceConfig();
+        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                context.getMainExecutor(),
+                (properties) -> onDeviceConfigChange(properties.getKeyset()));
+
+        final PowerManager powerManager = context.getSystemService(PowerManager.class);
+        mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
+                        | PowerManager.ON_AFTER_RELEASE,
+                UNDIM_DETECTOR_WAKE_LOCK);
+    }
+
+    /**
+     * Launches a message that figures out the screen transitions and detects user undims. Must be
+     * called by the parent that is trying to update the screen policy.
+     */
+    public void recordScreenPolicy(int newPolicy) {
+        if (newPolicy == mCurrentScreenPolicy) {
+            return;
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG,
+                    "Screen policy transition: " + mCurrentScreenPolicy + " -> " + newPolicy);
+        }
+
+        // update the current policy with the new one immediately so we don't accidentally get
+        // into a loop (which is possible if the switch below triggers a new policy).
+        final int currentPolicy = mCurrentScreenPolicy;
+        mCurrentScreenPolicy = newPolicy;
+
+        if (!mKeepScreenOnEnabled) {
+            return;
+        }
+
+        switch (currentPolicy) {
+            case POLICY_DIM:
+                if (newPolicy == POLICY_BRIGHT) {
+                    final long now = mClock.getCurrentTime();
+                    final long timeElapsedSinceFirstUndim = now - mUndimCounterStartedMillis;
+                    if (timeElapsedSinceFirstUndim >= mMaxDurationBetweenUndimsMillis) {
+                        reset();
+                    }
+                    if (mUndimCounter == 0) {
+                        mUndimCounterStartedMillis = now;
+                    }
+
+                    mUndimCounter++;
+
+                    if (DEBUG) {
+                        Slog.d(TAG, "User undim, counter=" + mUndimCounter
+                                + " (required=" + mUndimsRequired + ")"
+                                + ", timeElapsedSinceFirstUndim=" + timeElapsedSinceFirstUndim
+                                + " (max=" + mMaxDurationBetweenUndimsMillis + ")");
+                    }
+                    if (mUndimCounter >= mUndimsRequired) {
+                        reset();
+                        if (DEBUG) {
+                            Slog.d(TAG, "Acquiring a wake lock for " + mKeepScreenOnForMillis);
+                        }
+                        if (mWakeLock != null) {
+                            mUndimOccurredTime = mClock.getCurrentTime();
+                            mWakeLock.acquire(mKeepScreenOnForMillis);
+                        }
+                    }
+                } else {
+                    if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) {
+                        checkAndLogUndim(OUTCOME_TIMEOUT);
+                    }
+                    reset();
+                }
+                break;
+            case POLICY_BRIGHT:
+                if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) {
+                    checkAndLogUndim(OUTCOME_POWER_BUTTON);
+                }
+                if (newPolicy != POLICY_DIM) {
+                    reset();
+                }
+                break;
+        }
+    }
+
+    @VisibleForTesting
+    void reset() {
+        if (DEBUG) {
+            Slog.d(TAG, "Resetting the undim detector");
+        }
+        mUndimCounter = 0;
+        mUndimCounterStartedMillis = 0;
+        if (mWakeLock != null && mWakeLock.isHeld()) {
+            mWakeLock.release();
+        }
+    }
+
+    private boolean readKeepScreenOnNotificationEnabled() {
+        return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_ENABLED,
+                DEFAULT_KEEP_SCREEN_ON_ENABLED);
+    }
+
+    private long readKeepScreenOnForMillis() {
+        return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_FOR_MILLIS,
+                DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS);
+    }
+
+    private int readUndimsRequired() {
+        int undimsRequired = DeviceConfig.getInt(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                DEFAULT_UNDIMS_REQUIRED);
+
+        if (undimsRequired < 1 || undimsRequired > 5) {
+            Slog.e(TAG, "Provided undimsRequired=" + undimsRequired
+                    + " is not allowed [1, 5]; using the default=" + DEFAULT_UNDIMS_REQUIRED);
+            return DEFAULT_UNDIMS_REQUIRED;
+        }
+
+        return undimsRequired;
+    }
+
+    private long readMaxDurationBetweenUndimsMillis() {
+        return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
+                DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS);
+    }
+
+    private void onDeviceConfigChange(@NonNull Set<String> keys) {
+        for (String key : keys) {
+            Slog.i(TAG, "onDeviceConfigChange; key=" + key);
+            switch (key) {
+                case KEY_KEEP_SCREEN_ON_ENABLED:
+                case KEY_KEEP_SCREEN_ON_FOR_MILLIS:
+                case KEY_UNDIMS_REQUIRED:
+                case KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS:
+                    readValuesFromDeviceConfig();
+                    return;
+                default:
+                    Slog.i(TAG, "Ignoring change on " + key);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void readValuesFromDeviceConfig() {
+        mKeepScreenOnEnabled = readKeepScreenOnNotificationEnabled();
+        mKeepScreenOnForMillis = readKeepScreenOnForMillis();
+        mUndimsRequired = readUndimsRequired();
+        mMaxDurationBetweenUndimsMillis = readMaxDurationBetweenUndimsMillis();
+
+        Slog.i(TAG, "readValuesFromDeviceConfig():"
+                + "\nmKeepScreenOnForMillis=" + mKeepScreenOnForMillis
+                + "\nmKeepScreenOnNotificationEnabled=" + mKeepScreenOnEnabled
+                + "\nmUndimsRequired=" + mUndimsRequired);
+
+    }
+
+    /**
+     * The user interacted with the screen after an undim, indicating the phone is in use.
+     * We use this event for logging.
+     */
+    public void userActivity() {
+        if (mUndimOccurredTime != 1 && mInteractionAfterUndimTime == -1) {
+            mInteractionAfterUndimTime = mClock.getCurrentTime();
+        }
+    }
+
+    /**
+     * Checks and logs if an undim occurred.
+     *
+     * A log will occur if an undim seems to have resulted in a timeout or a direct screen off such
+     * as from a power button. Some outcomes may not be correctly assigned to a
+     * TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME value.
+     */
+    private void checkAndLogUndim(int outcome) {
+        if (mUndimOccurredTime != -1) {
+            long now = mClock.getCurrentTime();
+            FrameworkStatsLog.write(FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED,
+                    outcome,
+                    /* time_to_outcome_millis=*/  now - mUndimOccurredTime,
+                    /* time_to_first_interaction_millis= */
+                    mInteractionAfterUndimTime != -1 ? now - mInteractionAfterUndimTime : -1
+            );
+            mUndimOccurredTime = -1;
+            mInteractionAfterUndimTime = -1;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7713320..80bc16a 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wallpaper;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.app.WallpaperManager.COMMAND_REAPPLY;
 import static android.app.WallpaperManager.FLAG_LOCK;
 import static android.app.WallpaperManager.FLAG_SYSTEM;
@@ -2045,7 +2046,21 @@
         }
     }
 
+    private boolean hasCrossUserPermission() {
+        final int interactPermission =
+                mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL);
+        return interactPermission == PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
     public boolean hasNamedWallpaper(String name) {
+        final int callingUser = UserHandle.getCallingUserId();
+        final boolean allowCrossUser = hasCrossUserPermission();
+        if (DEBUG) {
+            Slog.d(TAG, "hasNamedWallpaper() caller " + Binder.getCallingUid()
+                    + " cross-user?: " + allowCrossUser);
+        }
+
         synchronized (mLock) {
             List<UserInfo> users;
             final long ident = Binder.clearCallingIdentity();
@@ -2055,6 +2070,11 @@
                 Binder.restoreCallingIdentity(ident);
             }
             for (UserInfo user: users) {
+                if (!allowCrossUser && callingUser != user.id) {
+                    // No cross-user information for callers without permission
+                    continue;
+                }
+
                 // ignore managed profiles
                 if (user.isManagedProfile()) {
                     continue;
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 3a4faf7..e02e867 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -21,6 +21,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.os.Process.INVALID_UID;
+import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -53,6 +55,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -64,6 +67,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.util.Slog;
 import android.view.RemoteAnimationDefinition;
@@ -74,6 +78,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.vr.VrManagerInternal;
 
@@ -557,20 +562,45 @@
 
     @Override
     public int getLaunchedFromUid(IBinder token) {
+        if (!canGetLaunchedFrom()) {
+            return INVALID_UID;
+        }
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-            return r != null ? r.launchedFromUid : android.os.Process.INVALID_UID;
+            return r != null ? r.launchedFromUid : INVALID_UID;
         }
     }
 
     @Override
     public String getLaunchedFromPackage(IBinder token) {
+        if (!canGetLaunchedFrom()) {
+            return null;
+        }
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
             return r != null ? r.launchedFromPackage : null;
         }
     }
 
+    /** Whether the caller can get the package or uid that launched its activity. */
+    private boolean canGetLaunchedFrom() {
+        final int uid = Binder.getCallingUid();
+        if (UserHandle.getAppId(uid) == SYSTEM_UID) {
+            return true;
+        }
+        final PackageManagerInternal pm = mService.mWindowManager.mPmInternal;
+        final AndroidPackage callingPkg = pm.getPackage(uid);
+        if (callingPkg == null) {
+            return false;
+        }
+        if (callingPkg.isSignedWithPlatformKey()) {
+            return true;
+        }
+        final String[] installerNames = pm.getKnownPackageNames(
+                PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.getUserId(uid));
+        return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]);
+    }
+
     @Override
     public void setRequestedOrientation(IBinder token, int requestedOrientation) {
         final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 308df2f..c2cfe0b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -656,6 +656,12 @@
     boolean mLastImeShown;
 
     /**
+     * When set to true, the IME insets will be frozen until the next app becomes IME input target.
+     * @see InsetsPolicy#adjustVisibilityForIme
+     */
+    boolean mImeInsetsFrozenUntilStartInput;
+
+    /**
      * A flag to determine if this AR is in the process of closing or entering PIP. This is needed
      * to help AR know that the app is in the process of closing but hasn't yet started closing on
      * the WM side.
@@ -1363,6 +1369,7 @@
         }
         if (newTask != null && isState(RESUMED)) {
             newTask.setResumedActivity(this, "onParentChanged");
+            mImeInsetsFrozenUntilStartInput = false;
         }
 
         if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -4759,6 +4766,7 @@
                     && imeInputTarget.getWindow().mActivityRecord == this
                     && mDisplayContent.mInputMethodWindow != null
                     && mDisplayContent.mInputMethodWindow.isVisible();
+            mImeInsetsFrozenUntilStartInput = true;
         }
 
         final DisplayContent displayContent = getDisplayContent();
@@ -5877,6 +5885,14 @@
             // closing activity having to wait until idle timeout to be stopped or destroyed if the
             // next activity won't report idle (e.g. repeated view animation).
             mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+
+            // If the activity is visible, but no windows are eligible to start input, unfreeze
+            // to avoid permanently frozen IME insets.
+            if (mImeInsetsFrozenUntilStartInput && getWindow(
+                    win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
+                    == null) {
+                mImeInsetsFrozenUntilStartInput = false;
+            }
         }
     }
 
@@ -7792,6 +7808,13 @@
         }
     }
 
+    @Override
+    void onResize() {
+        // Reset freezing IME insets flag when the activity resized.
+        mImeInsetsFrozenUntilStartInput = false;
+        super.onResize();
+    }
+
     /** Returns true if the configuration is compatible with this activity. */
     boolean isConfigurationCompatible(Configuration config) {
         final int orientation = getRequestedOrientation();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index dbc1116..ca696b7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3971,6 +3971,9 @@
     void updateImeInputAndControlTarget(WindowState target) {
         if (mImeInputTarget != target) {
             ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
+            if (target != null && target.mActivityRecord != null) {
+                target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
+            }
             setImeInputTarget(target);
             updateImeControlTarget();
         }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8c781a1..d417d56 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -39,6 +39,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
@@ -650,6 +651,7 @@
                 || type == TYPE_DOCK_DIVIDER
                 || type == TYPE_ACCESSIBILITY_OVERLAY
                 || type == TYPE_INPUT_CONSUMER
-                || type == TYPE_VOICE_INTERACTION;
+                || type == TYPE_VOICE_INTERACTION
+                || type == TYPE_STATUS_BAR_ADDITIONAL;
     }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f2f1926..a8e1c1c 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -211,7 +211,7 @@
     InsetsState getInsetsForWindow(WindowState target) {
         final InsetsState originalState = mStateController.getInsetsForWindow(target);
         final InsetsState state = adjustVisibilityForTransientTypes(originalState);
-        return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
+        return adjustVisibilityForIme(target, state, state == originalState);
     }
 
     /**
@@ -241,16 +241,37 @@
         return state;
     }
 
-    // Navigation bar insets is always visible to IME.
-    private static InsetsState adjustVisibilityForIme(InsetsState originalState,
+    private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
             boolean copyState) {
-        final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
-        if (originalNavSource != null && !originalNavSource.isVisible()) {
-            final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
-            final InsetsSource navSource = new InsetsSource(originalNavSource);
-            navSource.setVisible(true);
-            state.addSource(navSource);
-            return state;
+        if (w.mIsImWindow) {
+            // Navigation bar insets is always visible to IME.
+            final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
+            if (originalNavSource != null && !originalNavSource.isVisible()) {
+                final InsetsState state = copyState ? new InsetsState(originalState)
+                        : originalState;
+                final InsetsSource navSource = new InsetsSource(originalNavSource);
+                navSource.setVisible(true);
+                state.addSource(navSource);
+                return state;
+            }
+        } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
+            // During switching tasks with gestural navigation, if the IME is attached to
+            // one app window on that time, even the next app window is behind the IME window,
+            // conceptually the window should not receive the IME insets if the next window is
+            // not eligible IME requester and ready to show IME on top of it.
+            final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+            final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
+
+            if (shouldImeAttachedToApp && originalImeSource != null) {
+                final boolean imeVisibility =
+                        w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
+                final InsetsState state = copyState ? new InsetsState(originalState)
+                        : originalState;
+                final InsetsSource imeSource = new InsetsSource(originalImeSource);
+                imeSource.setVisible(imeVisibility);
+                state.addSource(imeSource);
+                return state;
+            }
         }
         return originalState;
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ec9187..5e642ce 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7061,6 +7061,7 @@
                             "requestScrollCapture: caught exception dispatching to window."
                                     + "token=%s", targetWindow.mClient.asBinder());
                     responseBuilder.setWindowTitle(targetWindow.getName());
+                    responseBuilder.setPackageName(targetWindow.getOwningPackage());
                     responseBuilder.setDescription(String.format("caught exception: %s", e));
                     listener.onScrollCaptureResponse(responseBuilder.build());
                 }
@@ -8606,8 +8607,9 @@
             if (imeTargetWindowTask == null) {
                 return false;
             }
-            final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId,
-                    false /* isLowResolution */);
+            final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
+                    imeTargetWindowTask.mUserId, false /* isLowResolution */,
+                    false /* restoreFromDisk */);
             return snapshot != null && snapshot.hasImeSurface();
         }
     }
diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp
new file mode 100644
index 0000000..35d754b
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "PackageInstallerTests",
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.runner",
+        "junit",
+        "kotlin-test",
+        "truth-prebuilt",
+    ],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+}
diff --git a/services/tests/PackageManager/packageinstaller/AndroidManifest.xml b/services/tests/PackageManager/packageinstaller/AndroidManifest.xml
new file mode 100644
index 0000000..d706258
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.packageinstaller.test">
+
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.packageinstaller.test"
+        />
+
+</manifest>
+
diff --git a/services/tests/PackageManager/packageinstaller/AndroidTest.xml b/services/tests/PackageManager/packageinstaller/AndroidTest.xml
new file mode 100644
index 0000000..c39285ff
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<configuration description="Test module config for PackageInstallerTests">
+    <option name="test-tag" value="PackageInstallerTests" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="PackageInstallerTests.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.packageinstaller.test" />
+    </test>
+</configuration>
diff --git a/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
new file mode 100644
index 0000000..d7d2726
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.test
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import androidx.test.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+
+class ExportedComponentTest {
+
+    private val context: Context = InstrumentationRegistry.getContext()
+
+    @Test
+    fun verifyNoExportedReceivers() {
+        val intent = Intent(Intent.ACTION_INSTALL_PACKAGE).apply {
+            data = Uri.parse("content://mockForTest")
+        }
+        val packageInstallers = context.packageManager.queryIntentActivities(intent,
+            PackageManager.MATCH_DEFAULT_ONLY or PackageManager.MATCH_DISABLED_COMPONENTS)
+            .map { it.activityInfo.packageName }
+            .distinct()
+            .map { context.packageManager.getPackageInfo(it, PackageManager.GET_RECEIVERS) }
+
+        assertThat(packageInstallers).isNotEmpty()
+
+        packageInstallers.forEach {
+            val exported = it.receivers.filter { it.exported }
+            assertWithMessage("Receivers should not be exported").that(exported).isEmpty()
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 17a5dcc..3cab5ec 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -28,6 +28,7 @@
     <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
     <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission
         android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
new file mode 100644
index 0000000..f94377f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import static com.android.server.power.ScreenUndimDetector.DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
+import static com.android.server.power.ScreenUndimDetector.KEY_KEEP_SCREEN_ON_ENABLED;
+import static com.android.server.power.ScreenUndimDetector.KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
+import static com.android.server.power.ScreenUndimDetector.KEY_UNDIMS_REQUIRED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.testing.TestableContext;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.testables.TestableDeviceConfig;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link com.android.server.power.ScreenUndimDetector}
+ */
+@RunWith(JUnit4.class)
+public class ScreenUndimDetectorTest {
+    private static final List<Integer> ALL_POLICIES =
+            Arrays.asList(POLICY_OFF,
+                    POLICY_DOZE,
+                    POLICY_DIM,
+                    POLICY_BRIGHT,
+                    POLICY_VR);
+
+    @ClassRule
+    public static final TestableContext sContext = new TestableContext(
+            InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+    @Rule
+    public TestableDeviceConfig.TestableDeviceConfigRule
+            mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+    private ScreenUndimDetector mScreenUndimDetector;
+
+    private final TestClock mClock = new TestClock();
+
+    private static class TestClock extends ScreenUndimDetector.InternalClock {
+        long mCurrentTime = 0;
+        @Override
+        public long getCurrentTime() {
+            return mCurrentTime;
+        }
+
+        public void advanceTime(long millisAdvanced) {
+            mCurrentTime += millisAdvanced;
+        }
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(1), false /*makeDefault*/);
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
+                Long.toString(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS),
+                false /*makeDefault*/);
+
+        mScreenUndimDetector = new ScreenUndimDetector(mClock);
+        mScreenUndimDetector.systemReady(sContext);
+    }
+
+    @Test
+    public void recordScreenPolicy_disabledByFlag_noop() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/);
+
+        setup();
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+    }
+
+    @Test
+    public void recordScreenPolicy_samePolicy_noop() {
+        for (int policy : ALL_POLICIES) {
+            setup();
+            mScreenUndimDetector.recordScreenPolicy(policy);
+            mScreenUndimDetector.recordScreenPolicy(policy);
+
+            assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        }
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToBright_extends() {
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue();
+    }
+
+    @Test
+    public void recordScreenPolicy_otherTransitions_doesNotExtend() {
+        for (int from : ALL_POLICIES) {
+            for (int to : ALL_POLICIES) {
+                if (from == POLICY_DIM && to == POLICY_BRIGHT) {
+                    continue;
+                }
+                setup();
+                mScreenUndimDetector.recordScreenPolicy(from);
+                mScreenUndimDetector.recordScreenPolicy(to);
+
+                assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+                assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+            }
+        }
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToBright_twoUndimsNeeded_extends() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue();
+    }
+
+    @Test
+    public void recordScreenPolicy_dimBrightDimOff_resetsCounter_doesNotExtend() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+    }
+
+    @Test
+    public void recordScreenPolicy_undimToOff_resetsCounter() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+    }
+
+    @Test
+    public void recordScreenPolicy_undimOffUndim_doesNotExtend() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        // undim
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        // off
+        mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+        // second undim
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1);
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToBright_tooFarApart_doesNotExtend() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        mClock.advanceTime(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS + 5);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1);
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToNonBright_resets() {
+        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+            setup();
+            mScreenUndimDetector.mUndimCounter = 1;
+            mScreenUndimDetector.mUndimCounterStartedMillis = 123;
+            mScreenUndimDetector.mWakeLock.acquire();
+
+            mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+            mScreenUndimDetector.recordScreenPolicy(to);
+
+            assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        }
+
+    }
+
+    @Test
+    public void recordScreenPolicy_brightToNonDim_resets() {
+        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+            setup();
+            mScreenUndimDetector.mUndimCounter = 1;
+            mScreenUndimDetector.mUndimCounterStartedMillis = 123;
+            mScreenUndimDetector.mWakeLock.acquire();
+
+            mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+            mScreenUndimDetector.recordScreenPolicy(to);
+
+            assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        }
+    }
+
+    @Test
+    public void recordScreenPolicy_otherTransitions_doesNotReset() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(3),
+                false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        for (int from : ALL_POLICIES) {
+            for (int to : ALL_POLICIES) {
+                if (from == POLICY_DIM && to != POLICY_BRIGHT) {
+                    continue;
+                }
+                if (from == POLICY_BRIGHT && to != POLICY_DIM) {
+                    continue;
+                }
+                mScreenUndimDetector.mCurrentScreenPolicy = POLICY_OFF;
+                mScreenUndimDetector.mUndimCounter = 1;
+                mScreenUndimDetector.mUndimCounterStartedMillis =
+                        SystemClock.currentThreadTimeMillis();
+
+                mScreenUndimDetector.recordScreenPolicy(from);
+                mScreenUndimDetector.recordScreenPolicy(to);
+
+                assertThat(mScreenUndimDetector.mUndimCounter).isNotEqualTo(0);
+                assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isNotEqualTo(0);
+            }
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
index 5012ca9..6e3f754 100644
--- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -210,7 +210,7 @@
         @Override
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                FaceDownDetector faceDownDetector) {
+                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
             return mNotifierMock;
         }
 
@@ -298,6 +298,7 @@
                         BatteryStats.SERVICE_NAME)),
                 mInjector.createSuspendBlocker(mService, "testBlocker"),
                 null,
+                null,
                 null);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 5eabc1b..3d64d4b 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -215,7 +215,7 @@
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                     SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                    FaceDownDetector faceDownDetector) {
+                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
                 return mNotifierMock;
             }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index f57c416..7bbf3e6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4793,6 +4793,52 @@
     }
 
     @Test
+    public void testSetNotificationsShownFromListener_protectsCrossUserInformation()
+            throws RemoteException {
+        Notification.Builder nb = new Notification.Builder(
+                mContext, mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+                "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
+                null, 0);
+        final NotificationRecord r =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+        r.setTextChanged(true);
+        mService.addNotification(r);
+
+        // no security exception!
+        mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
+
+        verify(mAppUsageStats, never()).reportInterruptiveNotification(
+                anyString(), anyString(), anyInt());
+    }
+
+    @Test
+    public void testCancelNotificationsFromListener_protectsCrossUserInformation()
+            throws RemoteException {
+        Notification.Builder nb = new Notification.Builder(
+                mContext, mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+                "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
+                null, 0);
+        final NotificationRecord r =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+        r.setTextChanged(true);
+        mService.addNotification(r);
+
+        // no security exception!
+        mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()});
+
+        waitForIdle();
+        assertEquals(1, mService.getNotificationRecordCount());
+    }
+
+    @Test
     public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
             throws RemoteException {
         final NotificationRecord r = generateNotificationRecord(
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 222c692..6b36fe8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -69,7 +69,7 @@
 
     @Before
     public void setUp() {
-        mDetector = new SingleKeyGestureDetector(mContext);
+        mDetector = new SingleKeyGestureDetector();
         initSingleKeyGestureRules();
         mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
         mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
@@ -78,7 +78,7 @@
     }
 
     private void initSingleKeyGestureRules() {
-        mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER,
+        mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(mContext, KEYCODE_POWER,
                 KEY_LONGPRESS | KEY_VERYLONGPRESS) {
             @Override
             int getMaxMultiPressCount() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 293e862a..6f04f17 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -39,6 +39,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -2816,6 +2817,73 @@
         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
     }
 
+    @Test
+    public void testImeInsetsFrozenFlag_resetWhenReparented() {
+        final ActivityRecord activity = createActivityWithTask();
+        final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app");
+        final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+        final Task newTask = new TaskBuilder(mSupervisor).build();
+        makeWindowVisible(app, imeWindow);
+        mDisplayContent.mInputMethodWindow = imeWindow;
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+
+        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+        activity.setState(RESUMED, "test");
+        activity.reparent(newTask, 0 /* top */, "test");
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+    }
+
+    @UseTestDisplay(addWindows = W_INPUT_METHOD)
+    @Test
+    public void testImeInsetsFrozenFlag_resetWhenResized() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        makeWindowVisibleAndDrawn(app, mImeWindow);
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+
+        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+        app.mActivityRecord.onResize();
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+    }
+
+    @UseTestDisplay(addWindows = W_INPUT_METHOD)
+    @Test
+    public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        makeWindowVisibleAndDrawn(app, mImeWindow);
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+
+        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        app.mActivityRecord.commitVisibility(false, false);
+        app.mActivityRecord.onWindowsGone();
+
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Expect IME insets frozen state will reset when the activity has no IME focusable window.
+        app.mActivityRecord.forAllWindowsUnchecked(w -> {
+            w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+            return true;
+        }, true);
+
+        app.mActivityRecord.commitVisibility(true, false);
+        app.mActivityRecord.onWindowsVisible();
+
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+    }
+
     private void assertHasStartingWindow(ActivityRecord atoken) {
         assertNotNull(atoken.mStartingSurface);
         assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a8e1753..8e7ba4bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -258,6 +258,7 @@
         final ActivityManagerInternal amInternal = mAmService.mInternal;
         spyOn(amInternal);
         doNothing().when(amInternal).trimApplications();
+        doNothing().when(amInternal).scheduleAppGcs();
         doNothing().when(amInternal).updateCpuStats();
         doNothing().when(amInternal).updateOomAdj();
         doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 92b670e..d88ac25 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -891,6 +891,40 @@
         assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
     }
 
+    @Test
+    public void testAdjustImeInsetsVisibilityWhenSwitchingApps() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+        final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+        spyOn(imeWindow);
+        doReturn(true).when(imeWindow).isVisible();
+        mDisplayContent.mInputMethodWindow = imeWindow;
+
+        final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+        controller.getImeSourceProvider().setWindow(imeWindow, null, null);
+
+        // Simulate app requests IME with updating all windows Insets State when IME is above app.
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+        assertTrue(mDisplayContent.shouldImeAttachedToApp());
+        controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+        controller.getImeSourceProvider().getSource().setVisible(true);
+        controller.updateAboveInsetsState(imeWindow, false);
+
+        // Expect all app windows behind IME can receive IME insets visible.
+        assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+        assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+        // Simulate app plays closing transition to app2.
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Verify the IME insets is visible on app, but not for app2 during app task switching.
+        assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+        assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+    }
+
     @UseTestDisplay(addWindows = { W_ACTIVITY })
     @Test
     public void testUpdateImeControlTargetWhenLeavingMultiWindow() {