Merge "Don't try to compress opus resources"
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
index eed1db0..c742df3 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -17,14 +17,14 @@
 package android.graphics.perftests;
 
 import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.Bitmap.Config;
+import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -43,7 +43,7 @@
         RenderNode child = RenderNode.create("child", null);
         child.setLeftTopRightBottom(50, 50, 100, 100);
 
-        DisplayListCanvas canvas = node.start(100, 100);
+        RecordingCanvas canvas = node.start(100, 100);
         node.end(canvas);
         canvas = child.start(50, 50);
         canvas.drawColor(Color.WHITE);
@@ -70,7 +70,7 @@
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         RenderNode node = RenderNode.create("benchmark", null);
 
-        DisplayListCanvas canvas = node.start(100, 100);
+        RecordingCanvas canvas = node.start(100, 100);
         node.end(canvas);
         Bitmap bitmap = Bitmap.createBitmap(80, 80, Config.ARGB_8888);
         Paint paint = new Paint();
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
index 3a4fc72..f9c3758 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
@@ -20,7 +20,6 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
-import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
index a283e06..d18aa51 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -17,17 +17,15 @@
 package android.graphics.perftests;
 
 import android.graphics.Outline;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.ArrayList;
-
 @LargeTest
 public class RenderNodePerfTest {
     @Rule
@@ -73,7 +71,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         RenderNode node = RenderNode.create("LinearLayout", null);
         while (state.keepRunning()) {
-            DisplayListCanvas canvas = node.start(100, 100);
+            RecordingCanvas canvas = node.start(100, 100);
             node.end(canvas);
         }
     }
@@ -82,7 +80,7 @@
     public void testStartEndDeepHierarchy() {
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         RenderNode[] nodes = new RenderNode[30];
-        DisplayListCanvas[] canvases = new DisplayListCanvas[nodes.length];
+        RecordingCanvas[] canvases = new RecordingCanvas[nodes.length];
         for (int i = 0; i < nodes.length; i++) {
             nodes[i] = RenderNode.create("LinearLayout", null);
         }
diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
index 64f2800..9245c1b 100644
--- a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
@@ -18,12 +18,12 @@
 import static android.text.Layout.Alignment.ALIGN_NORMAL;
 
 import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -120,7 +120,7 @@
         while (state.keepRunning()) {
 
             state.pauseTiming();
-            final DisplayListCanvas canvas = node.start(1200, 200);
+            final RecordingCanvas canvas = node.start(1200, 200);
             final int save = canvas.save();
             if (!mCached) Canvas.freeTextLayoutCaches();
             state.resumeTiming();
diff --git a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
index ad5a34e..a7972f5 100644
--- a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
@@ -17,11 +17,11 @@
 
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -107,7 +107,7 @@
         while (state.keepRunning()) {
 
             state.pauseTiming();
-            final DisplayListCanvas canvas = node.start(1200, 200);
+            final RecordingCanvas canvas = node.start(1200, 200);
             final int save = canvas.save();
             if (!mCached) Canvas.freeTextLayoutCaches();
             state.resumeTiming();
diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
index d98df05..00a6267 100644
--- a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
+++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
@@ -16,32 +16,16 @@
 
 package android.text;
 
-import static android.text.TextDirectionHeuristics.LTR;
-
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Typeface;
-import android.text.Layout;
-import android.text.style.TextAppearanceSpan;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.nio.CharBuffer;
-import java.util.Random;
 import java.util.Locale;
 
 @LargeTest
diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
index 1cd0ae1..33b1a47 100644
--- a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
@@ -16,30 +16,16 @@
 
 package android.text;
 
-import static android.text.TextDirectionHeuristics.LTR;
-
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Typeface;
-import android.text.Layout;
-import android.text.style.TextAppearanceSpan;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.nio.CharBuffer;
-import java.util.Random;
-
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class PrecomputedTextPerfTest {
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
index deb2b0a..b40dd6b 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
@@ -18,12 +18,12 @@
 import static android.text.Layout.Alignment.ALIGN_NORMAL;
 
 import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -119,7 +119,7 @@
         while (state.keepRunning()) {
 
             state.pauseTiming();
-            final DisplayListCanvas canvas = node.start(1200, 200);
+            final RecordingCanvas canvas = node.start(1200, 200);
             int save = canvas.save();
             if (!mCached) Canvas.freeTextLayoutCaches();
             state.resumeTiming();
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index e1a38a0..e224fa3 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -16,30 +16,19 @@
 
 package android.text;
 
-import static android.text.TextDirectionHeuristics.LTR;
-
+import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Typeface;
-import android.text.Layout;
-import android.text.style.TextAppearanceSpan;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.nio.CharBuffer;
-import java.util.Random;
-
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class StaticLayoutPerfTest {
@@ -256,7 +245,7 @@
             state.pauseTiming();
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             state.resumeTiming();
 
             layout.draw(c);
@@ -272,7 +261,7 @@
             final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             state.resumeTiming();
 
             layout.draw(c);
@@ -288,7 +277,7 @@
             final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             state.resumeTiming();
 
             layout.draw(c);
@@ -304,7 +293,7 @@
             final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             Canvas.freeTextLayoutCaches();
             state.resumeTiming();
 
@@ -321,7 +310,7 @@
             final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             Canvas.freeTextLayoutCaches();
             state.resumeTiming();
 
@@ -339,7 +328,7 @@
                     mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             state.resumeTiming();
 
             layout.draw(c);
@@ -356,7 +345,7 @@
                     mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             state.resumeTiming();
 
             layout.draw(c);
@@ -373,7 +362,7 @@
                     mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             Canvas.freeTextLayoutCaches();
             state.resumeTiming();
 
@@ -391,7 +380,7 @@
                     mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
             final StaticLayout layout =
                     StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
-            final DisplayListCanvas c = node.start(1200, 200);
+            final RecordingCanvas c = node.start(1200, 200);
             Canvas.freeTextLayoutCaches();
             state.resumeTiming();
 
diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
index aa505b5..22e516a 100644
--- a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
+++ b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
@@ -16,32 +16,15 @@
 
 package android.text;
 
-import static android.text.TextDirectionHeuristics.LTR;
-
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-
 import android.content.res.ColorStateList;
-import android.graphics.Canvas;
 import android.graphics.Typeface;
 import android.icu.text.UnicodeSet;
 import android.icu.text.UnicodeSetIterator;
-import android.text.Layout;
 import android.text.style.TextAppearanceSpan;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.nio.CharBuffer;
-import java.util.Random;
 import java.util.ArrayList;
+import java.util.Random;
 
 public class TextPerfUtils {
 
diff --git a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
index 4bbe404..25cc707 100644
--- a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
@@ -19,13 +19,13 @@
 import static android.view.View.MeasureSpec.UNSPECIFIED;
 
 import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 import android.widget.TextView;
 
 import org.junit.Rule;
@@ -128,7 +128,7 @@
         while (state.keepRunning()) {
 
             state.pauseTiming();
-            final DisplayListCanvas canvas = node.start(1200, 200);
+            final RecordingCanvas canvas = node.start(1200, 200);
             int save = canvas.save();
             textView.setTextLocale(Locale.UK);
             textView.setTextLocale(Locale.US);
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
index dc34b7f..434b8e5 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
@@ -16,46 +16,29 @@
 
 package android.widget;
 
-import static android.view.View.MeasureSpec.AT_MOST;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.UNSPECIFIED;
+import static android.widget.TextView.UNKNOWN_BORING;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Typeface;
 import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.text.PrecomputedText;
-import android.text.Layout;
 import android.text.BoringLayout;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
+import android.text.Layout;
+import android.text.PrecomputedText;
 import android.text.TextPaint;
-import android.text.style.TextAppearanceSpan;
-import android.view.LayoutInflater;
 import android.text.TextPerfUtils;
 import android.view.View.MeasureSpec;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-
-import com.android.perftests.core.R;
-
-import java.util.Random;
-import java.util.Locale;
 
 import org.junit.Before;
-import org.junit.Test;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertTrue;
-
-import static android.widget.TextView.UNKNOWN_BORING;
-
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class TextViewPrecomputedTextPerfTest {
@@ -360,7 +343,7 @@
             textView.setText(text);
             textView.measure(width, height);
             textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
-            final DisplayListCanvas c = node.start(
+            final RecordingCanvas c = node.start(
                 textView.getMeasuredWidth(), textView.getMeasuredHeight());
             textView.nullLayouts();
             Canvas.freeTextLayoutCaches();
@@ -386,7 +369,7 @@
             textView.setText(text);
             textView.measure(width, height);
             textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
-            final DisplayListCanvas c = node.start(
+            final RecordingCanvas c = node.start(
                 textView.getMeasuredWidth(), textView.getMeasuredHeight());
             textView.nullLayouts();
             Canvas.freeTextLayoutCaches();
@@ -414,7 +397,7 @@
             textView.setText(text);
             textView.measure(width, height);
             textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
-            final DisplayListCanvas c = node.start(
+            final RecordingCanvas c = node.start(
                 textView.getMeasuredWidth(), textView.getMeasuredHeight());
             textView.nullLayouts();
             Canvas.freeTextLayoutCaches();
@@ -443,7 +426,7 @@
             textView.setText(text);
             textView.measure(width, height);
             textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
-            final DisplayListCanvas c = node.start(
+            final RecordingCanvas c = node.start(
                 textView.getMeasuredWidth(), textView.getMeasuredHeight());
             textView.nullLayouts();
             Canvas.freeTextLayoutCaches();
diff --git a/api/current.txt b/api/current.txt
index 51df940..870c020 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -283,7 +283,6 @@
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
     field public static final int allowEmbedded = 16843765; // 0x10103f5
-    field public static final int allowForceDark = 16844172; // 0x101058c
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -638,6 +637,7 @@
     field public static final int fontVariationSettings = 16844144; // 0x1010570
     field public static final int fontWeight = 16844083; // 0x1010533
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
+    field public static final int forceDarkAllowed = 16844172; // 0x101058c
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
@@ -22662,6 +22662,7 @@
     method public boolean isBluetoothScoOn();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
+    method public static boolean isOffloadedPlaybackSupported(android.media.AudioFormat);
     method public boolean isSpeakerphoneOn();
     method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
@@ -22983,6 +22984,7 @@
     method public int getUnderrunCount();
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
+    method public void registerStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
     method public void release();
     method public int reloadStaticData();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
@@ -23003,6 +23005,7 @@
     method public deprecated int setStereoVolume(float, float);
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
+    method public void unregisterStreamEventCallback(android.media.AudioTrack.StreamEventCallback);
     method public int write(byte[], int, int);
     method public int write(byte[], int, int, int);
     method public int write(short[], int, int);
@@ -23036,6 +23039,7 @@
     method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
     method public android.media.AudioTrack.Builder setPerformanceMode(int);
     method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
@@ -23059,6 +23063,13 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
+  public static abstract class AudioTrack.StreamEventCallback {
+    ctor public AudioTrack.StreamEventCallback();
+    method public void onDataRequest(android.media.AudioTrack, int);
+    method public void onPresentationEnded(android.media.AudioTrack);
+    method public void onTearDown(android.media.AudioTrack);
+  }
+
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
@@ -29745,9 +29756,11 @@
   public class EGL15 {
     ctor public EGL15();
     method public static int eglClientWaitSync(android.opengl.EGLDisplay, android.opengl.EGLSync, int, long);
+    method public static android.opengl.EGLImage eglCreateImage(android.opengl.EGLDisplay, android.opengl.EGLContext, int, long, long[], int);
     method public static android.opengl.EGLSurface eglCreatePlatformPixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.nio.Buffer, long[], int);
     method public static android.opengl.EGLSurface eglCreatePlatformWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.nio.Buffer, long[], int);
     method public static android.opengl.EGLSync eglCreateSync(android.opengl.EGLDisplay, int, long[], int);
+    method public static boolean eglDestroyImage(android.opengl.EGLDisplay, android.opengl.EGLImage);
     method public static boolean eglDestroySync(android.opengl.EGLDisplay, android.opengl.EGLSync);
     method public static android.opengl.EGLDisplay eglGetPlatformDisplay(int, long, long[], int);
     method public static boolean eglGetSyncAttrib(android.opengl.EGLDisplay, android.opengl.EGLSync, int, long[], int);
@@ -36789,6 +36802,7 @@
     ctor public MediaStore();
     method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
     method public static android.net.Uri getMediaScannerUri();
+    method public static android.net.Uri getMediaUri(android.content.Context, android.net.Uri);
     method public static java.lang.String getVersion(android.content.Context);
     field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
@@ -48506,6 +48520,7 @@
     method public final boolean isFocusableInTouchMode();
     method public boolean isFocused();
     method public final boolean isFocusedByDefault();
+    method public boolean isForceDarkAllowed();
     method public boolean isHapticFeedbackEnabled();
     method public boolean isHardwareAccelerated();
     method public boolean isHorizontalFadingEdgeEnabled();
@@ -48692,6 +48707,7 @@
     method public void setFocusable(int);
     method public void setFocusableInTouchMode(boolean);
     method public void setFocusedByDefault(boolean);
+    method public void setForceDarkAllowed(boolean);
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
     method public void setForegroundTintList(android.content.res.ColorStateList);
diff --git a/api/system-current.txt b/api/system-current.txt
index 26036ea..7e51082 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -987,6 +987,7 @@
     field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
+    field public static final java.lang.String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
     field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
     field public static final java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
     field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index e915cc8..5dcb392b 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -114,7 +114,7 @@
 
 void BootAnimation::onFirstRef() {
     status_t err = mSession->linkToComposerDeath(this);
-    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
+    SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
     if (err == NO_ERROR) {
         run("BootAnimation", PRIORITY_DISPLAY);
     }
@@ -128,7 +128,7 @@
 void BootAnimation::binderDied(const wp<IBinder>&)
 {
     // woah, surfaceflinger died!
-    ALOGD("SurfaceFlinger died, exiting...");
+    SLOGD("SurfaceFlinger died, exiting...");
 
     // calling requestExit() is not enough here because the Surface code
     // might be blocked on a condition variable that will never be updated.
@@ -360,7 +360,7 @@
 
 bool BootAnimation::android()
 {
-    ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
+    SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
             elapsedRealtime());
     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
     initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
@@ -508,14 +508,14 @@
 static bool readFile(ZipFileRO* zip, const char* name, String8& outString)
 {
     ZipEntryRO entry = zip->findEntryByName(name);
-    ALOGE_IF(!entry, "couldn't find %s", name);
+    SLOGE_IF(!entry, "couldn't find %s", name);
     if (!entry) {
         return false;
     }
 
     FileMap* entryMap = zip->createEntryFileMap(entry);
     zip->releaseEntry(entry);
-    ALOGE_IF(!entryMap, "entryMap is null");
+    SLOGE_IF(!entryMap, "entryMap is null");
     if (!entryMap) {
         return false;
     }
@@ -616,7 +616,7 @@
     size_t length = strftime(timeBuff, TIME_LENGTH, timeFormat, timeInfo);
 
     if (length != TIME_LENGTH - 1) {
-        ALOGE("Couldn't format time; abandoning boot animation clock");
+        SLOGE("Couldn't format time; abandoning boot animation clock");
         mClockEnabled = false;
         return;
     }
@@ -654,13 +654,13 @@
 
         char pathType;
         if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
-            // ALOGD("> w=%d, h=%d, fps=%d", width, height, fps);
+            // SLOGD("> w=%d, h=%d, fps=%d", width, height, fps);
             animation.width = width;
             animation.height = height;
             animation.fps = fps;
         } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s",
                           &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
-            //ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
+            //SLOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
             //    pathType, count, pause, path, color, clockPos1, clockPos2);
             Animation::Part part;
             part.playUntilComplete = pathType == 'c';
@@ -670,7 +670,7 @@
             part.audioData = NULL;
             part.animation = NULL;
             if (!parseColor(color, part.backgroundColor)) {
-                ALOGE("> invalid color '#%s'", color);
+                SLOGE("> invalid color '#%s'", color);
                 part.backgroundColor[0] = 0.0f;
                 part.backgroundColor[1] = 0.0f;
                 part.backgroundColor[2] = 0.0f;
@@ -679,7 +679,7 @@
             animation.parts.add(part);
         }
         else if (strcmp(l, "$SYSTEM") == 0) {
-            // ALOGD("> SYSTEM");
+            // SLOGD("> SYSTEM");
             Animation::Part part;
             part.playUntilComplete = false;
             part.count = 1;
@@ -710,7 +710,7 @@
     while ((entry = zip->nextEntry(cookie)) != NULL) {
         const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
         if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
-            ALOGE("Error fetching entry file name");
+            SLOGE("Error fetching entry file name");
             continue;
         }
 
@@ -754,7 +754,7 @@
                                 }
                             }
                         } else {
-                            ALOGE("bootanimation.zip is compressed; must be only stored");
+                            SLOGE("bootanimation.zip is compressed; must be only stored");
                         }
                     }
                 }
@@ -782,7 +782,7 @@
                 frame.trimX = x;
                 frame.trimY = y;
             } else {
-                ALOGE("Error parsing trim.txt, line: %s", lineStr);
+                SLOGE("Error parsing trim.txt, line: %s", lineStr);
                 break;
             }
         }
@@ -876,7 +876,7 @@
     const int animationX = (mWidth - animation.width) / 2;
     const int animationY = (mHeight - animation.height) / 2;
 
-    ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
+    SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
             elapsedRealtime());
     for (size_t i=0 ; i<pcount ; i++) {
         const Animation::Part& part(animation.parts[i]);
@@ -949,7 +949,7 @@
 
                 nsecs_t now = systemTime();
                 nsecs_t delay = frameDuration - (now - lastFrame);
-                //ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
+                //SLOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
                 lastFrame = now;
 
                 if (delay > 0) {
@@ -1048,13 +1048,13 @@
 BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
 {
     if (mLoadedFiles.indexOf(fn) >= 0) {
-        ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
+        SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
             fn.string());
         return NULL;
     }
     ZipFileRO *zip = ZipFileRO::open(fn);
     if (zip == NULL) {
-        ALOGE("Failed to open animation zip \"%s\": %s",
+        SLOGE("Failed to open animation zip \"%s\": %s",
             fn.string(), strerror(errno));
         return NULL;
     }
@@ -1143,7 +1143,7 @@
     if (pollResult == 0) {
         return true;
     } else if (pollResult < 0) {
-        ALOGE("Could not poll inotify events");
+        SLOGE("Could not poll inotify events");
         return false;
     }
 
@@ -1152,7 +1152,7 @@
     if (length == 0) {
         return true;
     } else if (length < 0) {
-        ALOGE("Could not read inotify events");
+        SLOGE("Could not read inotify events");
         return false;
     }
 
@@ -1183,7 +1183,7 @@
 status_t BootAnimation::TimeCheckThread::readyToRun() {
     mInotifyFd = inotify_init();
     if (mInotifyFd < 0) {
-        ALOGE("Could not initialize inotify fd");
+        SLOGE("Could not initialize inotify fd");
         return NO_INIT;
     }
 
@@ -1191,7 +1191,7 @@
     if (mSystemWd < 0) {
         close(mInotifyFd);
         mInotifyFd = -1;
-        ALOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
+        SLOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
         return NO_INIT;
     }
 
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index d334f96..8fa2980 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -31,6 +31,7 @@
 #include <gui/ISurfaceComposer.h>
 
 #include <ui/DisplayInfo.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <system/graphics.h>
@@ -74,12 +75,12 @@
     }
 }
 
-static sk_sp<SkColorSpace> dataSpaceToColorSpace(android_dataspace d)
+static sk_sp<SkColorSpace> dataSpaceToColorSpace(ui::Dataspace d)
 {
     switch (d) {
-        case HAL_DATASPACE_V0_SRGB:
+        case ui::Dataspace::V0_SRGB:
             return SkColorSpace::MakeSRGB();
-        case HAL_DATASPACE_DISPLAY_P3:
+        case ui::Dataspace::DISPLAY_P3:
             return SkColorSpace::MakeRGB(
                     SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
         default:
@@ -87,12 +88,26 @@
     }
 }
 
-static uint32_t dataSpaceToInt(android_dataspace d)
+static ui::Dataspace pickBestDataspace(ui::ColorMode colorMode)
+{
+    switch (colorMode) {
+        case ui::ColorMode::SRGB:
+            return ui::Dataspace::V0_SRGB;
+        case ui::ColorMode::DISPLAY_P3:
+        case ui::ColorMode::BT2100_PQ:
+        case ui::ColorMode::BT2100_HLG:
+            return ui::Dataspace::DISPLAY_P3;
+        default:
+            return ui::Dataspace::V0_SRGB;
+    }
+}
+
+static uint32_t dataSpaceToInt(ui::Dataspace d)
 {
     switch (d) {
-        case HAL_DATASPACE_V0_SRGB:
+        case ui::Dataspace::V0_SRGB:
             return COLORSPACE_SRGB;
-        case HAL_DATASPACE_DISPLAY_P3:
+        case ui::Dataspace::DISPLAY_P3:
             return COLORSPACE_DISPLAY_P3;
         default:
             return COLORSPACE_UNKNOWN;
@@ -161,7 +176,6 @@
 
     void* base = NULL;
     uint32_t w, s, h, f;
-    android_dataspace d;
     size_t size = 0;
 
     // Maps orientations from DisplayInfo to ISurfaceComposer
@@ -197,8 +211,15 @@
     uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
 
     sp<GraphicBuffer> outBuffer;
-    status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */,
-            0 /* reqHeight */, false, captureOrientation, &outBuffer);
+    ui::Dataspace reqDataspace =
+        pickBestDataspace(SurfaceComposerClient::getActiveColorMode(display));
+
+    // Due to the fact that we hard code the way we write pixels into screenshot,
+    // we hard code RGBA_8888 here.
+    ui::PixelFormat reqPixelFormat = ui::PixelFormat::RGBA_8888;
+    status_t result = ScreenshotClient::capture(display, reqDataspace, reqPixelFormat, Rect(),
+                                                0 /* reqWidth */, 0 /* reqHeight */, false,
+                                                captureOrientation, &outBuffer);
     if (result != NO_ERROR) {
         close(fd);
         return 1;
@@ -222,12 +243,12 @@
     h = outBuffer->getHeight();
     s = outBuffer->getStride();
     f = outBuffer->getPixelFormat();
-    d = HAL_DATASPACE_UNKNOWN;
     size = s * h * bytesPerPixel(f);
 
     if (png) {
         const SkImageInfo info =
-            SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d));
+            SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType,
+                              dataSpaceToColorSpace(reqDataspace));
         SkPixmap pixmap(info, base, s * bytesPerPixel(f));
         struct FDWStream final : public SkWStream {
           size_t fBytesWritten = 0;
@@ -244,7 +265,7 @@
             notifyMediaScanner(fn);
         }
     } else {
-        uint32_t c = dataSpaceToInt(d);
+        uint32_t c = dataSpaceToInt(reqDataspace);
         write(fd, &w, 4);
         write(fd, &h, 4);
         write(fd, &f, 4);
@@ -261,4 +282,4 @@
     }
 
     return 0;
-}
\ No newline at end of file
+}
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 453bf7e..e33bd8c 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -64,10 +64,22 @@
     optional StateField option = 1 [default = STATE_FIELD_UNSET];
 }
 
+// Used to generate StatsLog.write APIs.
+enum LogMode {
+    MODE_UNSET = 0;
+    // Log fields as their actual types e.g., all primary data types.
+    // Or fields that are hardcoded in stats_log_api_gen tool e.g., AttributionNode
+    MODE_AUTOMATIC = 1;
+    // Log fields in their proto binary format. These fields will not be parsed in statsd
+    MODE_BYTES = 2;
+}
+
 extend google.protobuf.FieldOptions {
     // Flags to decorate an atom that presents a state change.
     optional StateAtomFieldOption state_field_option = 50000;
 
     // Flags to decorate the uid fields in an atom.
     optional bool is_uid = 50001 [default = false];
+
+    optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
 }
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index dfb40a9..d52dec1 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -22,6 +22,7 @@
 
 import "frameworks/base/cmds/statsd/src/atom_field_options.proto";
 import "frameworks/base/core/proto/android/app/enums.proto";
+import "frameworks/base/core/proto/android/app/settings_enums.proto";
 import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
@@ -185,6 +186,7 @@
         DiskIo disk_io = 10032;
         PowerProfile power_profile = 10033;
         ProcStats proc_stats_pkg_proc = 10034;
+        ProcessCpuTime process_cpu_time = 10035;
         NativeProcessMemoryState native_process_memory_state = 10036;
     }
 
@@ -1445,41 +1447,20 @@
  */
 message SettingsUIChanged {
     /**
-     * The action performed in this event
-     */
-    enum Action {
-        ACTION_UNKNOWN = 0;
-        PAGE_VISIBLE = 1;
-        PAGE_HIDE = 2;
-        PREF_CHANGE = 3;
-    }
-
-    /**
-     * Id for Settings pages. Each page must have its own unique Id.
-     */
-    enum PageId {
-      // Unknown page. Should not be used in production code.
-      PAGE_UNKNOWN = 0;
-
-      // Settings > Display > Lock screen display > On lock screen
-      LOCK_SCREEN_NOTIFICATION_CONTENT = 1584;
-    }
-
-    /**
      * Where this SettingsUIChange event comes from. For example, if
      * it's a PAGE_VISIBLE event, where the page is opened from.
      */
-    optional PageId attribution = 1;
+    optional android.app.settings.PageId attribution = 1;
 
     /**
      * What the UI action is.
      */
-    optional Action action = 2;
+    optional android.app.settings.Action action = 2;
 
     /**
      * Where the action is happening
      */
-    optional PageId pageId = 3;
+    optional android.app.settings.PageId pageId = 3;
 
     /**
      * What preference changed in this event.
@@ -2107,25 +2088,34 @@
     optional int32 importance = 7;
 
     // ID for the notification channel.
-    optional int32 channel_id = 8;
+    optional string channel_id = 8;
 
     // Importance for the notification channel.
     optional int32 channel_importance = 9;
 
+    // Application-supplied ID associated with the notifications group.
+    optional string group_id = 10;
+
     // Whether notification was a group summary.
-    optional bool group_summary = 10;
+    optional bool group_summary = 11;
 
-    // Time since notification was created in milliseconds.
-    optional int64 since_create_millis = 11;
+    // Reason for dismissal of a notification. This field is only meaningful for
+    // TYPE_DISMISS events.
+    optional int32 dismiss_reason = 12;
 
-    // Time since notification was interrupted in milliseconds.
-    optional int64 since_interruption_millis = 12;
+    // The first post time of notification, stable across updates.
+    optional int64 creation_millis = 13;
 
-    // Time since notification was updated in milliseconds.
-    optional int64 since_update_millis = 13;
+    // The most recent interruption time, or the creation time if no updates.
+    // Differs from update_millis because updates are filtered based on whether
+    // they actually interrupted the user.
+    optional int64 interruption_millis = 14;
 
-    // Time since notification was visible in milliseconds.
-    optional int64 since_visible_millis = 14;
+    // The most recent update time, or the creation time if no updates.
+    optional int64 update_millis = 15;
+
+    // The most recent visibility event.
+    optional int64 visible_millis = 16;
 }
 
 
@@ -3102,4 +3092,20 @@
     optional string restriction = 1;
     // Whether the restriction is enabled or disabled.
     optional bool enabled = 2;
+}
+
+/**
+ * Pulls process user time and system time. Puller takes a snapshot of all pids
+ * in the system and returns cpu stats for those that are working at the time.
+ * Dead pids will be dropped. Kernel processes are excluded.
+ * Min cool-down is 5 sec.
+ */
+message ProcessCpuTime {
+    optional int32 uid = 1 [(is_uid) = true];
+
+    optional string process_name = 2;
+    // Process cpu time in user space, cumulative from boot/process start
+    optional int64 user_time_millis = 3;
+    // Process cpu time in system space, cumulative from boot/process start
+    optional int64 system_time_millis = 4;
 }
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 1a9ba8a..ba626f8 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -229,6 +229,11 @@
         // PowerProfile constants for power model calculations.
         {android::util::POWER_PROFILE,
          {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
+        // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses.
+        {android::util::PROCESS_CPU_TIME,
+            {{} /* additive fields */, {} /* non additive fields */,
+             5 * NS_PER_SEC /* min cool-down in seconds*/,
+             new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 805e583..2498d9f 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -25,15 +25,16 @@
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 
+using android::util::AtomsInfo;
 using android::util::FIELD_COUNT_REPEATED;
 using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FIXED64;
 using android::util::FIELD_TYPE_FLOAT;
 using android::util::FIELD_TYPE_INT32;
 using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_UINT64;
-using android::util::FIELD_TYPE_FIXED64;
 using android::util::FIELD_TYPE_MESSAGE;
 using android::util::FIELD_TYPE_STRING;
+using android::util::FIELD_TYPE_UINT64;
 using android::util::ProtoOutputStream;
 
 namespace android {
@@ -294,8 +295,9 @@
 // }
 //
 //
-void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size_t* index,
-                                       int depth, int prefix, ProtoOutputStream* protoOutput) {
+void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& dims,
+                                       size_t* index, int depth, int prefix,
+                                       ProtoOutputStream* protoOutput) {
     size_t count = dims.size();
     while (*index < count) {
         const auto& dim = dims[*index];
@@ -319,9 +321,31 @@
                 case FLOAT:
                     protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
                     break;
-                case STRING:
-                    protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
+                case STRING: {
+                    bool isBytesField = false;
+                    // Bytes field is logged via string format in log_msg format. So here we check
+                    // if this string field is a byte field.
+                    std::map<int, std::vector<int>>::const_iterator itr;
+                    if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) !=
+                                              AtomsInfo::kBytesFieldAtoms.end()) {
+                        const std::vector<int>& bytesFields = itr->second;
+                        for (int bytesField : bytesFields) {
+                            if (bytesField == fieldNum) {
+                                // This is a bytes field
+                                isBytesField = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (isBytesField) {
+                        protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
+                                           (const char*)dim.mValue.str_value.c_str(),
+                                           dim.mValue.str_value.length());
+                    } else {
+                        protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
+                    }
                     break;
+                }
                 case STORAGE:
                     protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
                                        (const char*)dim.mValue.storage_value.data(),
@@ -342,7 +366,7 @@
             }
             // Directly jump to the leaf value because the repeated position field is implied
             // by the position of the sub msg in the parent field.
-            writeFieldValueTreeToStreamHelper(dims, index, valueDepth,
+            writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
                                               dim.mField.getPrefix(valueDepth), protoOutput);
             if (msg_token != 0) {
                 protoOutput->end(msg_token);
@@ -359,7 +383,7 @@
     uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
 
     size_t index = 0;
-    writeFieldValueTreeToStreamHelper(values, &index, 0, 0, protoOutput);
+    writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
     protoOutput->end(atomToken);
 }
 
diff --git a/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java b/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java
index ae3e5a1..cc4e386 100644
--- a/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java
@@ -31,7 +31,10 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Formatter;
 import java.util.logging.Level;
+import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 public class TestDrive {
@@ -68,6 +71,12 @@
         mIsPushedAtom = atomId < PULL_ATOM_START;
 
         TestDrive testDrive = new TestDrive();
+        TestDriveFormatter formatter = new TestDriveFormatter();
+        ConsoleHandler handler = new ConsoleHandler();
+        handler.setFormatter(formatter);
+        logger.addHandler(handler);
+        logger.setUseParentHandlers(false);
+
         try {
             StatsdConfig config = testDrive.createConfig(atomId);
             if (config == null) {
@@ -79,7 +88,8 @@
             logger.info(config.toString());
             if (mIsPushedAtom) {
                 logger.info(
-                        "Now please play with the device to trigger the event. All events should be dumped after 1 min ...");
+                        "Now please play with the device to trigger the event. All events should "
+                                + "be dumped after 1 min ...");
                 Thread.sleep(60_000);
             } else {
                 // wait for 2 min
@@ -140,7 +150,7 @@
 
         // Check result
         if (process.waitFor() == 0) {
-            logger.info("Success!");
+            logger.fine("Success!");
         } else {
             // Abnormal termination: Log command parameters and output and throw ExecutionException
             logger.log(Level.SEVERE, out.toString());
@@ -235,8 +245,8 @@
         ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
         // Really should be only one metric.
         if (report.getMetricsCount() != 1) {
-            logger.log(Level.SEVERE, "Only one report metric expected, got "
-                    + report.getMetricsCount());
+            logger.log(Level.SEVERE,
+                    "Only one report metric expected, got " + report.getMetricsCount());
             return;
         }
 
@@ -283,4 +293,10 @@
                     + "allowed_log_source: \"AID_BLUETOOTH\"\n"
                     + "\n"
                     + "hash_strings_in_metric_report: false";
+
+    public static class TestDriveFormatter extends Formatter {
+        public String format(LogRecord record) {
+            return record.getMessage() + "\n";
+        }
+    }
 }
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index be9ccec..2d51038 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -6414,6 +6414,38 @@
 HPLandroid/util/proto/EncodedBuffer;->writeFromThisBuffer(II)V
 HPLandroid/util/proto/EncodedBuffer;->writeRawBuffer([BII)V
 HPLandroid/util/proto/EncodedBuffer;->writeRawFixed64(J)V
+HPLandroid/util/proto/ProtoInputStream;-><init>(Ljava/io/InputStream;I)V
+HPLandroid/util/proto/ProtoInputStream;-><init>(Ljava/io/InputStream;)V
+HPLandroid/util/proto/ProtoInputStream;-><init>([B)V
+HPLandroid/util/proto/ProtoInputStream;->getFieldNumber()I
+HPLandroid/util/proto/ProtoInputStream;->getWireType()I
+HPLandroid/util/proto/ProtoInputStream;->getOffset()I
+HPLandroid/util/proto/ProtoInputStream;->nextField()I
+HPLandroid/util/proto/ProtoInputStream;->isNextField(J)Z
+HPLandroid/util/proto/ProtoInputStream;->readDouble(J)D
+HPLandroid/util/proto/ProtoInputStream;->readFloat(J)F
+HPLandroid/util/proto/ProtoInputStream;->readInt(J)I
+HPLandroid/util/proto/ProtoInputStream;->readLong(J)J
+HPLandroid/util/proto/ProtoInputStream;->readBoolean(J)Z
+HPLandroid/util/proto/ProtoInputStream;->readString(J)Ljava/lang/String;
+HPLandroid/util/proto/ProtoInputStream;->readBytes(J)[B
+HPLandroid/util/proto/ProtoInputStream;->start(J)J
+HPLandroid/util/proto/ProtoInputStream;->end(J)V
+HPLandroid/util/proto/ProtoInputStream;->readTag()V
+HPLandroid/util/proto/ProtoInputStream;->decodeZigZag32(I)I
+HPLandroid/util/proto/ProtoInputStream;->decodeZigZag64(J)J
+HPLandroid/util/proto/ProtoInputStream;->readVarint()J
+HPLandroid/util/proto/ProtoInputStream;->readFixed32()I
+HPLandroid/util/proto/ProtoInputStream;->readFixed64()J
+HPLandroid/util/proto/ProtoInputStream;->readRawBytes(I)[B
+HPLandroid/util/proto/ProtoInputStream;->readRawString(I)Ljava/lang/String;
+HPLandroid/util/proto/ProtoInputStream;->fillBuffer()V
+HPLandroid/util/proto/ProtoInputStream;->skip()V
+HPLandroid/util/proto/ProtoInputStream;->incOffset(I)V
+HPLandroid/util/proto/ProtoInputStream;->checkPacked(J)V
+HPLandroid/util/proto/ProtoInputStream;->assertFieldNumber(J)V
+HPLandroid/util/proto/ProtoInputStream;->assertWireType(I)V
+HPLandroid/util/proto/ProtoInputStream;->assertFreshData()V
 HPLandroid/util/proto/ProtoOutputStream;-><init>(Ljava/io/FileDescriptor;)V
 HPLandroid/util/proto/ProtoOutputStream;-><init>(Ljava/io/OutputStream;)V
 HPLandroid/util/proto/ProtoOutputStream;->compactIfNecessary()V
@@ -58580,6 +58612,7 @@
 Landroid/util/apk/ZipUtils;
 Landroid/util/jar/StrictJarFile;
 Landroid/util/proto/EncodedBuffer;
+Landroid/util/proto/ProtoInputStream;
 Landroid/util/proto/ProtoOutputStream;
 Landroid/view/-$$Lambda$FocusFinder$FocusSorter$h0f2ZYL6peSaaEeCCkAoYs_YZvU;
 Landroid/view/-$$Lambda$FocusFinder$FocusSorter$kW7K1t9q7Y62V38r-7g6xRzqqq8;
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 1a8a32e..95bcf0e 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -3227,7 +3227,7 @@
 android.view.DisplayEventReceiver
 android.view.DisplayInfo
 android.view.DisplayInfo$1
-android.view.DisplayListCanvas
+android.graphics.RecordingCanvas
 android.view.FallbackEventHandler
 android.view.FocusFinder
 android.view.FocusFinder$1
@@ -3305,8 +3305,8 @@
 android.view.OrientationEventListener$SensorEventListenerImpl
 android.view.PointerIcon
 android.view.PointerIcon$1
-android.view.RenderNode
-android.view.RenderNode$NoImagePreloadHolder
+android.graphics.RenderNode
+android.graphics.RenderNode$NoImagePreloadHolder
 android.view.RenderNodeAnimator
 android.view.RenderNodeAnimator$1
 android.view.RenderNodeAnimatorSetHelper
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9d3c5c6..4756bf4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1425,60 +1425,10 @@
             PrintWriter pw = new FastPrintWriter(
                     new FileOutputStream(pfd.getFileDescriptor()));
             PrintWriterPrinter printer = new PrintWriterPrinter(pw);
-            SQLiteDebug.dump(printer, args);
-
-            if (isSystem) {
-                dumpDatabaseFileSizes(pw, Environment.getDataSystemDirectory(), true);
-                dumpDatabaseFileSizes(pw, Environment.getDataSystemDeDirectory(), true);
-                dumpDatabaseFileSizes(pw, Environment.getDataSystemCeDirectory(), true);
-            } else {
-                Context context = getApplication();
-                if (context != null) {
-                    dumpDatabaseFileSizes(pw,
-                            getDatabasesDir(context.createDeviceProtectedStorageContext()),
-                            false);
-                    dumpDatabaseFileSizes(pw,
-                            getDatabasesDir(context.createCredentialProtectedStorageContext()),
-                            false);
-                }
-            }
+            SQLiteDebug.dump(printer, args, isSystem);
             pw.flush();
         }
 
-        private void dumpDatabaseFileSizes(PrintWriter pw, File dir, boolean isSystem) {
-            final File[] files = dir.listFiles();
-            if (files == null || files.length == 0) {
-                return;
-            }
-            Arrays.sort(files, (a, b) -> a.getName().compareTo(b.getName()));
-
-            boolean needHeader = true;
-            for (File f : files) {
-                if (isSystem) {
-                    // If it's the system server, the directory contains other files too, so
-                    // filter by file extensions.
-                    // (If it's an app, just print all files because they may not use *.db
-                    // extension.)
-                    final String name = f.getName();
-                    if (!(name.endsWith(".db") || name.endsWith(".db-wal")
-                            || name.endsWith(".db-journal"))) {
-                        continue;
-                    }
-                }
-                if (needHeader) {
-                    pw.println();
-                    pw.println("Database files in " + dir.getAbsolutePath() + ":");
-                    needHeader = false;
-                }
-
-                pw.print("  ");
-                pw.print(f.getName());
-                pw.print("  ");
-                pw.print(f.length());
-                pw.println(" bytes");
-            }
-        }
-
         @Override
         public void dumpDbInfo(final ParcelFileDescriptor pfd, final String[] args) {
             if (mSystemThread) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a30ae79..3b05566 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1283,8 +1283,8 @@
             AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION
             AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS
             AppOpsManager.MODE_ALLOWED, // CALL_PHONE
-            AppOpsManager.MODE_DEFAULT, // READ_SMS
-            AppOpsManager.MODE_DEFAULT, // WRITE_SMS
+            AppOpsManager.MODE_ALLOWED, // READ_SMS
+            AppOpsManager.MODE_IGNORED, // WRITE_SMS
             AppOpsManager.MODE_DEFAULT, // RECEIVE_SMS
             AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST
             AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 599c2d2..a2a6b9b 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -36,11 +36,9 @@
 import android.database.Cursor;
 import android.database.IContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.ImageDecoder;
 import android.graphics.ImageDecoder.ImageInfo;
 import android.graphics.ImageDecoder.Source;
-import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -55,7 +53,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.DocumentsContract;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
@@ -3255,4 +3252,13 @@
             }
         });
     }
+
+    /** {@hide} */
+    public static void onDbCorruption(String tag, String message, Throwable stacktrace) {
+        try {
+            getContentService().onDbCorruption(tag, message, Log.getStackTraceString(stacktrace));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index a55dd31..1d02375 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -185,4 +185,6 @@
     Bundle getCache(in String packageName, in Uri key, int userId);
 
     void resetTodayStats();
+
+    void onDbCorruption(String tag, String message, String stacktrace);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c0463e9..ea1a2fe 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1908,6 +1908,22 @@
     @SystemApi
     public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
 
+    /**
+     * Activity action: Launch UI to review app uses of permissions.
+     * <p>
+     * Input: Nothing
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REVIEW_PERMISSION_USAGE =
+            "android.intent.action.REVIEW_PERMISSION_USAGE";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent broadcast actions (see action variable).
diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java
index 7fa2b40..cf019e1 100755
--- a/core/java/android/database/DefaultDatabaseErrorHandler.java
+++ b/core/java/android/database/DefaultDatabaseErrorHandler.java
@@ -15,14 +15,14 @@
  */
 package android.database;
 
-import java.io.File;
-import java.util.List;
-
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.util.Log;
 import android.util.Pair;
 
+import java.io.File;
+import java.util.List;
+
 /**
  * Default class used to define the action to take when database corruption is reported
  * by sqlite.
@@ -52,6 +52,7 @@
      */
     public void onCorruption(SQLiteDatabase dbObj) {
         Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());
+        SQLiteDatabase.wipeDetected(dbObj.getPath(), "corruption");
 
         // is the corruption detected even before database could be 'opened'?
         if (!dbObj.isOpen()) {
@@ -99,7 +100,7 @@
         }
         Log.e(TAG, "deleting the database file: " + fileName);
         try {
-            SQLiteDatabase.deleteDatabase(new File(fileName));
+            SQLiteDatabase.deleteDatabase(new File(fileName), /*removeCheckFile=*/ false);
         } catch (Exception e) {
             /* print warning and ignore exception */
             Log.w(TAG, "delete failed: " + e.getMessage());
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 5c4f16a..20505ca 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -34,6 +34,7 @@
 import dalvik.system.CloseGuard;
 
 import java.io.File;
+import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
@@ -414,6 +415,10 @@
         final String newLocale = mConfiguration.locale.toString();
         nativeRegisterLocalizedCollators(mConnectionPtr, newLocale);
 
+        if (!mConfiguration.isInMemoryDb()) {
+            checkDatabaseWiped();
+        }
+
         // If the database is read-only, we cannot modify the android metadata table
         // or existing indexes.
         if (mIsReadOnlyConnection) {
@@ -449,6 +454,36 @@
         }
     }
 
+    private void checkDatabaseWiped() {
+        if (!SQLiteGlobal.checkDbWipe()) {
+            return;
+        }
+        try {
+            final File checkFile = new File(mConfiguration.path
+                    + SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX);
+
+            final boolean hasMetadataTable = executeForLong(
+                    "SELECT count(*) FROM sqlite_master"
+                            + " WHERE type='table' AND name='android_metadata'", null, null) > 0;
+            final boolean hasCheckFile = checkFile.exists();
+
+            if (!mIsReadOnlyConnection && !hasCheckFile) {
+                // Create the check file, unless it's a readonly connection,
+                // in which case we can't create the metadata table anyway.
+                checkFile.createNewFile();
+            }
+
+            if (!hasMetadataTable && hasCheckFile) {
+                // Bad. The DB is gone unexpectedly.
+                SQLiteDatabase.wipeDetected(mConfiguration.path, "unknown");
+            }
+
+        } catch (RuntimeException | IOException ex) {
+            SQLiteDatabase.wtfAsSystemServer(TAG,
+                    "Unexpected exception while checking for wipe", ex);
+        }
+    }
+
     // Called by SQLiteConnectionPool only.
     void reconfigure(SQLiteDatabaseConfiguration configuration) {
         mOnlyAllowReadOnlyOperations = false;
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 3ee348b..dbc1766 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -24,6 +24,7 @@
 import android.os.OperationCanceledException;
 import android.os.SystemClock;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.PrefixPrinter;
 import android.util.Printer;
@@ -34,6 +35,7 @@
 import dalvik.system.CloseGuard;
 
 import java.io.Closeable;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -1105,9 +1107,12 @@
      * @param printer The printer to receive the dump, not null.
      * @param verbose True to dump more verbose information.
      */
-    public void dump(Printer printer, boolean verbose) {
+    public void dump(Printer printer, boolean verbose, ArraySet<String> directories) {
         Printer indentedPrinter = PrefixPrinter.create(printer, "    ");
         synchronized (mLock) {
+            if (directories != null) {
+                directories.add(new File(mConfiguration.path).getParent());
+            }
             printer.println("Connection pool for " + mConfiguration.path + ":");
             printer.println("  Open: " + mIsOpen);
             printer.println("  Max connections: " + mMaxConnectionPoolSize);
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index eb5c720..f9c2c3e 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -22,6 +22,8 @@
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
@@ -34,6 +36,7 @@
 import android.os.OperationCanceledException;
 import android.os.SystemProperties;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
@@ -45,9 +48,14 @@
 
 import java.io.File;
 import java.io.FileFilter;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -808,6 +816,12 @@
      * @return True if the database was successfully deleted.
      */
     public static boolean deleteDatabase(@NonNull File file) {
+        return deleteDatabase(file, /*removeCheckFile=*/ true);
+    }
+
+
+    /** @hide */
+    public static boolean deleteDatabase(@NonNull File file, boolean removeCheckFile) {
         if (file == null) {
             throw new IllegalArgumentException("file must not be null");
         }
@@ -818,6 +832,9 @@
         deleted |= new File(file.getPath() + "-shm").delete();
         deleted |= new File(file.getPath() + "-wal").delete();
 
+        // This file is not a standard SQLite file, so don't update the deleted flag.
+        new File(file.getPath() + SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX).delete();
+
         File dir = file.getParentFile();
         if (dir != null) {
             final String prefix = file.getName() + "-mj";
@@ -2170,21 +2187,61 @@
      * Dump detailed information about all open databases in the current process.
      * Used by bug report.
      */
-    static void dumpAll(Printer printer, boolean verbose) {
+    static void dumpAll(Printer printer, boolean verbose, boolean isSystem) {
+        // Use this ArraySet to collect file paths.
+        final ArraySet<String> directories = new ArraySet<>();
+
         for (SQLiteDatabase db : getActiveDatabases()) {
-            db.dump(printer, verbose);
+            db.dump(printer, verbose, isSystem, directories);
+        }
+
+        // Dump DB files in the directories.
+        if (directories.size() > 0) {
+            final String[] dirs = directories.toArray(new String[directories.size()]);
+            Arrays.sort(dirs);
+            for (String dir : dirs) {
+                dumpDatabaseDirectory(printer, new File(dir), isSystem);
+            }
         }
     }
 
-    private void dump(Printer printer, boolean verbose) {
+    private void dump(Printer printer, boolean verbose, boolean isSystem, ArraySet directories) {
         synchronized (mLock) {
             if (mConnectionPoolLocked != null) {
                 printer.println("");
-                mConnectionPoolLocked.dump(printer, verbose);
+                mConnectionPoolLocked.dump(printer, verbose, directories);
             }
         }
     }
 
+    private static void dumpDatabaseDirectory(Printer pw, File dir, boolean isSystem) {
+        pw.println("");
+        pw.println("Database files in " + dir.getAbsolutePath() + ":");
+        final File[] files = dir.listFiles();
+        if (files == null || files.length == 0) {
+            pw.println("  [none]");
+            return;
+        }
+        Arrays.sort(files, (a, b) -> a.getName().compareTo(b.getName()));
+
+        for (File f : files) {
+            if (isSystem) {
+                // If called within the system server, the directory contains other files too, so
+                // filter by file extensions.
+                // (If it's an app, just print all files because they may not use *.db
+                // extension.)
+                final String name = f.getName();
+                if (!(name.endsWith(".db") || name.endsWith(".db-wal")
+                        || name.endsWith(".db-journal")
+                        || name.endsWith(SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX))) {
+                    continue;
+                }
+            }
+            pw.println(String.format("  %-40s %7db %s", f.getName(), f.length(),
+                    SQLiteDatabase.getFileTimestamps(f.getAbsolutePath())));
+        }
+    }
+
     /**
      * Returns list of full pathnames of all attached databases including the main database
      * by executing 'pragma database_list' on the database.
@@ -2611,7 +2668,7 @@
                 return this;
             }
 
-            /**
+            /**w
              * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>
              * .
              * @return
@@ -2646,5 +2703,34 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface DatabaseOpenFlags {}
 
+    /** @hide */
+    public static void wipeDetected(String filename, String reason) {
+        wtfAsSystemServer(TAG, "DB wipe detected:"
+                + " package=" + ActivityThread.currentPackageName()
+                + " reason=" + reason
+                + " file=" + filename
+                + " " + getFileTimestamps(filename)
+                + " checkfile " + getFileTimestamps(filename + SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX),
+                new Throwable("STACKTRACE"));
+    }
+
+    /** @hide */
+    public static String getFileTimestamps(String path) {
+        try {
+            BasicFileAttributes attr = Files.readAttributes(
+                    FileSystems.getDefault().getPath(path), BasicFileAttributes.class);
+            return "ctime=" + attr.creationTime()
+                    + " mtime=" + attr.lastModifiedTime()
+                    + " atime=" + attr.lastAccessTime();
+        } catch (IOException e) {
+            return "[unable to obtain timestamp]";
+        }
+    }
+
+    /** @hide */
+    static void wtfAsSystemServer(String tag, String message, Throwable stacktrace) {
+        Log.e(tag, message, stacktrace);
+        ContentResolver.onDbCorruption(tag, message, stacktrace);
+    }
 }
 
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index 1c66204..f220205 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -189,6 +189,11 @@
      * @param args Command-line arguments supplied to dumpsys dbinfo
      */
     public static void dump(Printer printer, String[] args) {
+        dump(printer, args, false);
+    }
+
+    /** @hide */
+    public static void dump(Printer printer, String[] args, boolean isSystem) {
         boolean verbose = false;
         for (String arg : args) {
             if (arg.equals("-v")) {
@@ -196,6 +201,6 @@
             }
         }
 
-        SQLiteDatabase.dumpAll(printer, verbose);
+        SQLiteDatabase.dumpAll(printer, verbose, isSystem);
     }
 }
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index 67e5f65..ff286fd 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -42,6 +42,9 @@
     /** @hide */
     public static final String SYNC_MODE_FULL = "FULL";
 
+    /** @hide */
+    static final String WIPE_CHECK_FILE_SUFFIX = "-wipecheck";
+
     private static final Object sLock = new Object();
 
     private static int sDefaultPageSize;
@@ -181,4 +184,8 @@
                         com.android.internal.R.integer.db_wal_truncate_size));
     }
 
+    /** @hide */
+    public static boolean checkDbWipe() {
+        return true;
+    }
 }
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 5de89e3..56da719 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -130,30 +130,42 @@
      * {@link PendingIntent} through a {@link BroadcastReceiver}, and maps an {@link Intent} to a
      * {@link ContextHubClientCallback}.
      *
-     * @param intent    The PendingIntent to register for this client
-     * @param nanoAppId the unique ID of the nanoapp to receive events for
+     * @param pendingIntent the PendingIntent to register for this client
+     * @param nanoAppId     the unique ID of the nanoapp to receive events for
      * @return true on success, false otherwise
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
-    public boolean registerIntent(@NonNull PendingIntent intent, long nanoAppId) {
-        // TODO: Implement this
-        return false;
+    public boolean registerIntent(@NonNull PendingIntent pendingIntent, long nanoAppId) {
+        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");
+
+        try {
+            return mClientProxy.registerIntent(pendingIntent, nanoAppId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
      * Unregisters an intent previously registered via {@link #registerIntent(PendingIntent, long)}.
      * If this intent has not been registered for this client, this method returns false.
      *
+     * @param pendingIntent the PendingIntent to unregister
+     *
      * @return true on success, false otherwise
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
-    public boolean unregisterIntent(@NonNull PendingIntent intent) {
-        // TODO: Implement this
-        return false;
+    public boolean unregisterIntent(@NonNull PendingIntent pendingIntent) {
+        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");
+
+        try {
+            return mClientProxy.unregisterIntent(pendingIntent);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index f94d69b..b0b77f3 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -73,7 +73,7 @@
      *
      * @hide
      */
-    public static final String EXTRA_NANOAPP_ID = "android.location.hardware.extra.NANOAPP_ID";
+    public static final String EXTRA_NANOAPP_ID = "android.hardware.location.extra.NANOAPP_ID";
 
     /**
      * An extra of type int describing the nanoapp-specific abort code.
@@ -81,14 +81,14 @@
      * @hide
      */
     public static final String EXTRA_NANOAPP_ABORT_CODE =
-            "android.location.hardware.extra.NANOAPP_ABORT_CODE";
+            "android.hardware.location.extra.NANOAPP_ABORT_CODE";
 
     /**
      * An extra of type {@link NanoAppMessage} describing contents of a message from a nanoapp.
      *
      * @hide
      */
-    public static final String EXTRA_MESSAGE = "android.location.hardware.extra.MESSAGE";
+    public static final String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE";
 
     /**
      * Constants describing the type of events from a Context Hub.
@@ -800,22 +800,22 @@
      * through {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} or
      * equivalent at an earlier time.
      *
-     * @param intent   the intent that is associated with a client
-     * @param hubInfo  the hub to attach this client to
-     * @param callback the notification callback to register
-     * @param executor the executor to invoke the callback
+     * @param pendingIntent the PendingIntent that has been registered with a client
+     * @param hubInfo       the hub to attach this client to
+     * @param callback      the notification callback to register
+     * @param executor      the executor to invoke the callback
      * @return the registered client object
      *
-     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or the intent
+     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
      *                                  was not associated with a client
      * @throws IllegalStateException    if there were too many registered clients at the service
-     * @throws NullPointerException     if intent, hubInfo, callback, or executor is null
+     * @throws NullPointerException     if pendingIntent, hubInfo, callback, or executor is null
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     @NonNull public ContextHubClient createClient(
-            @NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
+            @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
             @NonNull ContextHubClientCallback callback,
             @NonNull @CallbackExecutor Executor executor) {
         // TODO: Implement this
@@ -823,26 +823,27 @@
     }
 
     /**
-     * Equivalent to {@link #createClient(Intent, ContextHubInfo, ContextHubClientCallback,
+     * Equivalent to {@link #createClient(PendingIntent, ContextHubInfo, ContextHubClientCallback,
      * Executor)} with the executor using the main thread's Looper.
      *
-     * @param intent   the intent that is associated with a client
-     * @param hubInfo  the hub to attach this client to
-     * @param callback the notification callback to register
+     * @param pendingIntent the PendingIntent that has been registered with a client
+     * @param hubInfo       the hub to attach this client to
+     * @param callback      the notification callback to register
      * @return the registered client object
      *
-     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or the intent
+     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
      *                                  was not associated with a client
      * @throws IllegalStateException    if there were too many registered clients at the service
-     * @throws NullPointerException     if intent, hubInfo, or callback is null
+     * @throws NullPointerException     if pendingIntent, hubInfo, or callback is null
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     @NonNull public ContextHubClient createClient(
-            @NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
+            @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
             @NonNull ContextHubClientCallback callback) {
-        return createClient(intent, hubInfo, callback, new HandlerExecutor(Handler.getMain()));
+        return createClient(
+                pendingIntent, hubInfo, callback, new HandlerExecutor(Handler.getMain()));
     }
 
     /**
diff --git a/core/java/android/hardware/location/IContextHubClient.aidl b/core/java/android/hardware/location/IContextHubClient.aidl
index d81126a..7559cd5 100644
--- a/core/java/android/hardware/location/IContextHubClient.aidl
+++ b/core/java/android/hardware/location/IContextHubClient.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.location;
 
+import android.app.PendingIntent;
 import android.hardware.location.NanoAppMessage;
 
 /**
@@ -28,4 +29,10 @@
 
     // Closes the connection with the Context Hub
     void close();
+
+    // Registers a PendingIntent with the client
+    boolean registerIntent(in PendingIntent intent, long nanoAppId);
+
+    // Unregisters a PendingIntent from the client
+    boolean unregisterIntent(in PendingIntent intent);
 }
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 838765b..e970747 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -131,6 +132,14 @@
     @UnsupportedAppUsage
     public native int stopRecognition(int soundModelHandle);
 
+    /**
+     * Get the current state of a {@link SoundTrigger.SoundModel}
+     * @param soundModelHandle The sound model handle indicating which model's state to return
+     * @return - {@link SoundTrigger#RecognitionEvent} in case of success
+     *         - null in case of an error or if not supported
+     */
+    public native SoundTrigger.RecognitionEvent getModelState(int soundModelHandle);
+
     private class NativeEventHandlerDelegate {
         private final Handler mHandler;
 
@@ -207,4 +216,3 @@
         }
     }
 }
-
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 0982d65..843db6d 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -41,8 +41,7 @@
 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
     private static final String TAG = "InputMethodWrapper";
-    
-    private static final int DO_FINISH_INPUT = 60;
+
     private static final int DO_DISPLAY_COMPLETIONS = 65;
     private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
     private static final int DO_UPDATE_SELECTION = 90;
@@ -89,9 +88,6 @@
         }
 
         switch (msg.what) {
-            case DO_FINISH_INPUT:
-                mInputMethodSession.finishInput();
-                return;
             case DO_DISPLAY_COMPLETIONS:
                 mInputMethodSession.displayCompletions((CompletionInfo[])msg.obj);
                 return;
@@ -150,11 +146,6 @@
     }
 
     @Override
-    public void finishInput() {
-        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
-    }
-
-    @Override
     public void displayCompletions(CompletionInfo[] completions) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(
                 DO_DISPLAY_COMPLETIONS, completions));
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index f947b5e..8b6194c 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -28,6 +28,8 @@
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 
+import dalvik.annotation.optimization.CriticalNative;
+
 import libcore.io.IoUtils;
 import libcore.util.NativeAllocationRegistry;
 
@@ -373,6 +375,54 @@
     public static final native int getThreadStrictModePolicy();
 
     /**
+     * Sets the work source for this thread.
+     *
+     * <p>All the following binder calls on this thread will use the provided work source.
+     *
+     * <p>The concept of worksource is similar to {@link WorkSource}. However, for performance
+     * reasons, we only support one UID. This UID represents the original user responsible for the
+     * binder calls.
+     *
+     * <p>A typical use case would be
+     * <pre>
+     * Binder.setThreadWorkSource(uid);
+     * try {
+     *   // Call an API.
+     * } finally {
+     *   Binder.clearThreadWorkSource();
+     * }
+     * </pre>
+     *
+     * @param workSource The original UID responsible for the binder call.
+     * @return The previously set work source.
+     * @hide
+     **/
+    @CriticalNative
+    public static final native int setThreadWorkSource(int workSource);
+
+    /**
+     * Returns the work source set by the caller.
+     *
+     * Unlike {@link Binder#getCallingUid()}, this result of this method cannot be trusted. The
+     * caller can set the value to whatever he wants. Only use this value if you trust the calling
+     * uid.
+     *
+     * @return The original UID responsible for the binder transaction.
+     * @hide
+     */
+    @CriticalNative
+    public static final native int getThreadWorkSource();
+
+    /**
+     * Clears the work source on this thread.
+     *
+     * @return The previously set work source.
+     * @hide
+     **/
+    @CriticalNative
+    public static final native int clearThreadWorkSource();
+
+    /**
      * Flush any Binder commands pending in the current thread to the kernel
      * driver.  This can be
      * useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8ea061e..e0b2c78 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -557,6 +557,7 @@
             ServiceType.FORCE_ALL_APPS_STANDBY,
             ServiceType.OPTIONAL_SENSORS,
             ServiceType.AOD,
+            ServiceType.QUICK_DOZE,
     })
     public @interface ServiceType {
         int NULL = 0;
@@ -586,6 +587,11 @@
          * Whether to disable non-essential sensors. (e.g. edge sensors.)
          */
         int OPTIONAL_SENSORS = 13;
+
+        /**
+         * Whether to go into Deep Doze as soon as the screen turns off or not.
+         */
+        int QUICK_DOZE = 15;
     }
 
     /**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0f64c45..379d28c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -1003,11 +1003,38 @@
     public static final int PROC_OUT_LONG = 0x2000;
     /** @hide */
     public static final int PROC_OUT_FLOAT = 0x4000;
-    
-    /** @hide */
+
+    /**
+     * Read and parse a {@code proc} file in the given format.
+     *
+     * <p>The format is a list of integers, where every integer describes a variable in the file. It
+     * specifies how the variable is syntactically terminated (e.g. {@link Process#PROC_SPACE_TERM},
+     * {@link Process#PROC_TAB_TERM}, {@link Process#PROC_ZERO_TERM}).
+     *
+     * <p>If the variable should be parsed and returned to the caller, the termination type should
+     * be binary OR'd with the type of output (e.g. {@link Process#PROC_OUT_STRING}, {@link
+     * Process#PROC_OUT_LONG}, {@link Process#PROC_OUT_FLOAT}.
+     *
+     * <p>If the variable is wrapped in quotation marks it should be binary OR'd with {@link
+     * Process#PROC_QUOTES}. If the variable is wrapped in parentheses it should be binary OR'd with
+     * {@link Process#PROC_PARENS}.
+     *
+     * <p>If the variable is not formatted as a string and should be cast directly from characters
+     * to a long, the {@link Process#PROC_CHAR} integer should be binary OR'd.
+     *
+     * <p>If the terminating character can be repeated, the {@link Process#PROC_COMBINE} integer
+     * should be binary OR'd.
+     *
+     * @param file the path of the {@code proc} file to read
+     * @param format the format of the file
+     * @param outStrings the parsed {@code String}s from the file
+     * @param outLongs the parsed {@code long}s from the file
+     * @param outFloats the parsed {@code float}s from the file
+     * @hide
+     */
     public static final native boolean readProcFile(String file, int[] format,
             String[] outStrings, long[] outLongs, float[] outFloats);
-    
+
     /** @hide */
     public static final native boolean parseProcLine(byte[] buffer, int startIndex, 
             int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 954d18a..67e52aa 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -731,6 +731,8 @@
     public static final String EXTRA_PARENT_URI = "parentUri";
     /** {@hide} */
     public static final String EXTRA_URI = "uri";
+    /** {@hide} */
+    public static final String EXTRA_URI_PERMISSIONS = "uriPermissions";
 
     /**
      * @see #createWebLinkIntent(ContentResolver, Uri, Bundle)
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f5660b9..57f33f0 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -46,9 +46,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 
-import libcore.io.IoUtils;
-
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -82,6 +79,11 @@
      */
     public static final String RETRANSLATE_CALL = "update_titles";
 
+    /** {@hide} */
+    public static final String GET_DOCUMENT_URI_CALL = "get_document_uri";
+    /** {@hide} */
+    public static final String GET_MEDIA_URI_CALL = "get_media_uri";
+
     /**
      * This is for internal use by the media scanner only.
      * Name of the (optional) Uri parameter that determines whether to skip deleting
@@ -2275,84 +2277,62 @@
     }
 
     /**
-     * Gets a URI backed by a {@link DocumentsProvider} that points to the same media
-     * file as the specified mediaUri. This allows apps who have permissions to access
-     * media files in Storage Access Framework to perform file operations through that
-     * on media files.
+     * Return a {@link DocumentsProvider} Uri that is an equivalent to the given
+     * {@link MediaStore} Uri.
      * <p>
-     * Note: this method doesn't grant any URI permission. Callers need to obtain
-     * permission before calling this method. One way to obtain permission is through
-     * a 3-step process:
-     * <ol>
-     *     <li>Call {@link android.os.storage.StorageManager#getStorageVolume(File)} to
-     *     obtain the {@link android.os.storage.StorageVolume} of a media file;</li>
+     * This allows apps with Storage Access Framework permissions to convert
+     * between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
+     * to the same underlying item. Note that this method doesn't grant any new
+     * permissions; callers must already hold permissions obtained with
+     * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
      *
-     *     <li>Invoke the intent returned by
-     *     {@link android.os.storage.StorageVolume#createAccessIntent(String)} to
-     *     obtain the access of the volume or one of its specific subdirectories;</li>
-     *
-     *     <li>Check whether permission is granted and take persistent permission.</li>
-     * </ol>
-     * @param mediaUri the media URI which document URI is requested
-     * @return the document URI
+     * @param mediaUri The {@link MediaStore} Uri to convert.
+     * @return An equivalent {@link DocumentsProvider} Uri. Returns {@code null}
+     *         if no equivalent was found.
+     * @see #getMediaUri(Context, Uri)
      */
     public static Uri getDocumentUri(Context context, Uri mediaUri) {
+        final ContentResolver resolver = context.getContentResolver();
+        final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
 
-        try {
-            final ContentResolver resolver = context.getContentResolver();
-
-            final String path = getFilePath(resolver, mediaUri);
-            final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
-
-            return getDocumentUri(resolver, path, uriPermissions);
+        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
+            final Bundle in = new Bundle();
+            in.putParcelable(DocumentsContract.EXTRA_URI, mediaUri);
+            in.putParcelableList(DocumentsContract.EXTRA_URI_PERMISSIONS, uriPermissions);
+            final Bundle out = client.call(GET_DOCUMENT_URI_CALL, null, in);
+            return out.getParcelable(DocumentsContract.EXTRA_URI);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
-    private static String getFilePath(ContentResolver resolver, Uri mediaUri)
-            throws RemoteException {
+    /**
+     * Return a {@link MediaStore} Uri that is an equivalent to the given
+     * {@link DocumentsProvider} Uri.
+     * <p>
+     * This allows apps with Storage Access Framework permissions to convert
+     * between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
+     * to the same underlying item. Note that this method doesn't grant any new
+     * permissions; callers must already hold permissions obtained with
+     * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
+     *
+     * @param documentUri The {@link DocumentsProvider} Uri to convert.
+     * @return An equivalent {@link MediaStore} Uri. Returns {@code null} if no
+     *         equivalent was found.
+     * @see #getDocumentUri(Context, Uri)
+     */
+    public static Uri getMediaUri(Context context, Uri documentUri) {
+        final ContentResolver resolver = context.getContentResolver();
+        final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
 
-        try (ContentProviderClient client =
-                     resolver.acquireUnstableContentProviderClient(AUTHORITY)) {
-            final Cursor c = client.query(
-                    mediaUri,
-                    new String[]{ MediaColumns.DATA },
-                    null, /* selection */
-                    null, /* selectionArg */
-                    null /* sortOrder */);
-
-            final String path;
-            try {
-                if (c.getCount() == 0) {
-                    throw new IllegalStateException("Not found media file under URI: " + mediaUri);
-                }
-
-                if (!c.moveToFirst()) {
-                    throw new IllegalStateException("Failed to move cursor to the first item.");
-                }
-
-                path = c.getString(0);
-            } finally {
-                IoUtils.closeQuietly(c);
-            }
-
-            return path;
-        }
-    }
-
-    private static Uri getDocumentUri(
-            ContentResolver resolver, String path, List<UriPermission> uriPermissions)
-            throws RemoteException {
-
-        try (ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
-                DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
+        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
             final Bundle in = new Bundle();
-            in.putParcelableList(
-                    DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY + ".extra.uriPermissions",
-                    uriPermissions);
-            final Bundle out = client.call("getDocumentId", path, in);
+            in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+            in.putParcelableList(DocumentsContract.EXTRA_URI_PERMISSIONS, uriPermissions);
+            final Bundle out = client.call(GET_MEDIA_URI_CALL, null, in);
             return out.getParcelable(DocumentsContract.EXTRA_URI);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
         }
     }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ad64021..80e8f78 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10907,6 +10907,7 @@
          * idle_pending_to                  (long)
          * max_idle_pending_to              (long)
          * idle_pending_factor              (float)
+         * quick_doze_delay_to              (long)
          * idle_to                          (long)
          * max_idle_to                      (long)
          * idle_factor                      (float)
@@ -10940,6 +10941,11 @@
          * gps_mode                          (int)
          * adjust_brightness_disabled        (boolean)
          * adjust_brightness_factor          (float)
+         * force_all_apps_standby            (boolean)
+         * force_background_check            (boolean)
+         * optional_sensors_disabled         (boolean)
+         * aod_disabled                      (boolean)
+         * quick_doze_enabled                (boolean)
          * </pre>
          * @hide
          * @see com.android.server.power.BatterySaverPolicy
diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java
index fa7b067..98ed217 100644
--- a/core/java/android/view/GhostView.java
+++ b/core/java/android/view/GhostView.java
@@ -18,6 +18,8 @@
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.widget.FrameLayout;
 
 import java.util.ArrayList;
@@ -46,8 +48,8 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (canvas instanceof DisplayListCanvas) {
-            DisplayListCanvas dlCanvas = (DisplayListCanvas) canvas;
+        if (canvas instanceof RecordingCanvas) {
+            RecordingCanvas dlCanvas = (RecordingCanvas) canvas;
             mView.mRecreateDisplayList = true;
             RenderNode renderNode = mView.updateDisplayListIfDirty();
             if (renderNode.isValid()) {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index e48bcfd..9d31bd1 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -22,6 +22,8 @@
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 import android.util.SparseIntArray;
 
 import com.android.internal.util.VirtualRefBasePtr;
@@ -286,8 +288,8 @@
         setTarget(mViewTarget.mRenderNode);
     }
 
-    /** Sets the animation target to the owning view of the DisplayListCanvas */
-    public void setTarget(DisplayListCanvas canvas) {
+    /** Sets the animation target to the owning view of the RecordingCanvas */
+    public void setTarget(RecordingCanvas canvas) {
         setTarget(canvas.mNode);
     }
 
@@ -405,7 +407,7 @@
         return listeners;
     }
 
-    long getNativeAnimator() {
+    public long getNativeAnimator() {
         return mNativePtr.get();
     }
 
diff --git a/core/java/android/view/RenderNodeAnimatorSetHelper.java b/core/java/android/view/RenderNodeAnimatorSetHelper.java
index e1ef059..d222e07 100644
--- a/core/java/android/view/RenderNodeAnimatorSetHelper.java
+++ b/core/java/android/view/RenderNodeAnimatorSetHelper.java
@@ -16,6 +16,8 @@
 package android.view;
 
 import android.animation.TimeInterpolator;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
 
 import com.android.internal.view.animation.FallbackLUTInterpolator;
 import com.android.internal.view.animation.NativeInterpolatorFactory;
@@ -29,10 +31,12 @@
  */
 public class RenderNodeAnimatorSetHelper {
 
-    public static RenderNode getTarget(DisplayListCanvas recordingCanvas) {
+    /** checkstyle @hide */
+    public static RenderNode getTarget(RecordingCanvas recordingCanvas) {
         return recordingCanvas.mNode;
     }
 
+    /** checkstyle @hide */
     public static long createNativeInterpolator(TimeInterpolator interpolator, long
             duration) {
         if (interpolator == null) {
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6fb1bba..f3cb376 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -22,7 +22,9 @@
 import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.graphics.SurfaceTexture;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -889,13 +891,13 @@
     private final class HwuiContext {
         private final RenderNode mRenderNode;
         private long mHwuiRenderer;
-        private DisplayListCanvas mCanvas;
+        private RecordingCanvas mCanvas;
         private final boolean mIsWideColorGamut;
 
         HwuiContext(boolean isWideColorGamut) {
             mRenderNode = RenderNode.create("HwuiCanvas", null);
             mRenderNode.setClipToBounds(false);
-            mRenderNode.setAllowForceDark(false);
+            mRenderNode.setForceDarkAllowed(false);
             mIsWideColorGamut = isWideColorGamut;
             mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
                     isWideColorGamut);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index e71182c..67f9399 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -30,6 +30,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.RenderNode;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
diff --git a/core/java/android/view/TextureLayer.java b/core/java/android/view/TextureLayer.java
index 35a886f..d89d634 100644
--- a/core/java/android/view/TextureLayer.java
+++ b/core/java/android/view/TextureLayer.java
@@ -31,7 +31,7 @@
  *
  * @hide
  */
-final class TextureLayer {
+public final class TextureLayer {
     private ThreadedRenderer mRenderer;
     private VirtualRefBasePtr mFinalizer;
 
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 997e48fe..0175ba2 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -23,6 +23,7 @@
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.graphics.drawable.Drawable;
@@ -343,7 +344,7 @@
         properties (alpha, layer paint) affect all of the content of a TextureView. */
 
         if (canvas.isHardwareAccelerated()) {
-            DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+            RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
 
             TextureLayer layer = getTextureLayer();
             if (layer != null) {
@@ -351,7 +352,7 @@
                 applyTransformMatrix();
 
                 mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
-                displayListCanvas.drawTextureLayer(layer);
+                recordingCanvas.drawTextureLayer(layer);
             }
         }
     }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 42690ce..c1ab4d4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -24,7 +24,9 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Point;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -693,7 +695,7 @@
         updateViewTreeDisplayList(view);
 
         if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
-            DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
+            RecordingCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
             try {
                 final int saveCount = canvas.save();
                 canvas.translate(mInsetLeft, mInsetTop);
@@ -770,7 +772,7 @@
          *
          * @param canvas The Canvas used to render the view.
          */
-        void onPreDraw(DisplayListCanvas canvas);
+        void onPreDraw(RecordingCanvas canvas);
 
         /**
          * Invoked after a view is drawn by a threaded renderer.
@@ -778,7 +780,7 @@
          *
          * @param canvas The Canvas used to render the view.
          */
-        void onPostDraw(DisplayListCanvas canvas);
+        void onPostDraw(RecordingCanvas canvas);
     }
 
     /**
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index 06b73dd..6fb32e3 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -165,7 +165,11 @@
     public TouchDelegateInfo getTouchDelegateInfo() {
         if (mTouchDelegateInfo == null) {
             final ArrayMap<Region, View> targetMap = new ArrayMap<>(1);
-            targetMap.put(new Region(mBounds), mDelegateView);
+            Rect bounds = mBounds;
+            if (bounds == null) {
+                bounds = new Rect();
+            }
+            targetMap.put(new Region(bounds), mDelegateView);
             mTouchDelegateInfo = new TouchDelegateInfo(targetMap);
         }
         return mTouchDelegateInfo;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cc58b89..1157b28 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -57,9 +57,11 @@
 import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.RenderNode;
 import android.graphics.Shader;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -5540,6 +5542,10 @@
                     break;
                 case com.android.internal.R.styleable.View_accessibilityHeading:
                     setAccessibilityHeading(a.getBoolean(attr, false));
+                    break;
+                case R.styleable.View_forceDarkAllowed:
+                    mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true));
+                    break;
             }
         }
 
@@ -15284,11 +15290,9 @@
      * If a theme is isLightTheme="false", then force dark is globally disabled for that theme.
      *
      * @param allow Whether or not to allow force dark.
-     *
-     * @hide
      */
-    public void setAllowForceDark(boolean allow) {
-        if (mRenderNode.setAllowForceDark(allow)) {
+    public void setForceDarkAllowed(boolean allow) {
+        if (mRenderNode.setForceDarkAllowed(allow)) {
             // Currently toggling force-dark requires a new display list push to apply
             // TODO: Make it not clobber the display list so this is just a damageSelf() instead
             invalidate();
@@ -15296,15 +15300,13 @@
     }
 
     /**
-     * See {@link #setAllowForceDark(boolean)}
+     * See {@link #setForceDarkAllowed(boolean)}
      *
      * @return true if force dark is allowed (default), false if it is disabled
-     *
-     * @hide
      */
     @ViewDebug.ExportedProperty(category = "drawing")
-    public boolean getAllowForceDark() {
-        return mRenderNode.getAllowForceDark();
+    public boolean isForceDarkAllowed() {
+        return mRenderNode.isForceDarkAllowed();
     }
 
     /**
@@ -19233,7 +19235,7 @@
             int height = mBottom - mTop;
             int layerType = getLayerType();
 
-            final DisplayListCanvas canvas = renderNode.start(width, height);
+            final RecordingCanvas canvas = renderNode.start(width, height);
 
             try {
                 if (layerType == LAYER_TYPE_SOFTWARE) {
@@ -20250,7 +20252,7 @@
         if (!drawingWithDrawingCache) {
             if (drawingWithRenderNode) {
                 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-                ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
+                ((RecordingCanvas) canvas).drawRenderNode(renderNode);
             } else {
                 // Fast path for layouts with no backgrounds
                 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
@@ -20581,7 +20583,7 @@
             final RenderNode renderNode = mBackgroundRenderNode;
             if (renderNode != null && renderNode.isValid()) {
                 setBackgroundRenderNodeProperties(renderNode);
-                ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
+                ((RecordingCanvas) canvas).drawRenderNode(renderNode);
                 return;
             }
         }
@@ -20633,7 +20635,7 @@
         final Rect bounds = drawable.getBounds();
         final int width = bounds.width();
         final int height = bounds.height();
-        final DisplayListCanvas canvas = renderNode.start(width, height);
+        final RecordingCanvas canvas = renderNode.start(width, height);
 
         // Reverse left/top translation done by drawable canvas, which will
         // instead be applied by rendernode's LTRB bounds below. This way, the
diff --git a/core/java/android/view/ViewAnimationHostBridge.java b/core/java/android/view/ViewAnimationHostBridge.java
index 58f555d..e0fae21 100644
--- a/core/java/android/view/ViewAnimationHostBridge.java
+++ b/core/java/android/view/ViewAnimationHostBridge.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.graphics.RenderNode;
+
 /**
  * Maps a View to a RenderNode's AnimationHost
  *
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8dd0347..292e933 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -23,7 +23,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Picture;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -601,7 +603,7 @@
         }
 
         if (view.isHardwareAccelerated()) {
-            DisplayListCanvas canvas = node.start(dm.widthPixels, dm.heightPixels);
+            RecordingCanvas canvas = node.start(dm.widthPixels, dm.heightPixels);
             try {
                 return profileViewOperation(view, () -> view.draw(canvas));
             } finally {
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index e3e2069..a0ab362 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.graphics.RenderNode;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bef8e8f..170c783 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -51,8 +51,10 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.PorterDuff;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.RenderNode;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
@@ -1094,15 +1096,21 @@
     private void updateForceDarkMode() {
         if (mAttachInfo.mThreadedRenderer == null) return;
 
-        boolean nightMode = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
-        TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
-        boolean isLightTheme = a.getBoolean(R.styleable.Theme_isLightTheme, false);
-        a.recycle();
+        boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
 
-        boolean changed = mAttachInfo.mThreadedRenderer.setForceDark(nightMode);
-        changed |= mAttachInfo.mThreadedRenderer.getRootNode().setAllowForceDark(isLightTheme);
+        // Allow debug.hwui.force_dark to override the target SDK check
+        if (useAutoDark && !SystemProperties.getBoolean("debug.hwui.force_dark", false)) {
+            useAutoDark = mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q;
+        }
 
-        if (changed) {
+        if (useAutoDark) {
+            TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
+            useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
+                    && a.getBoolean(R.styleable.Theme_forceDarkAllowed, true);
+            a.recycle();
+        }
+
+        if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) {
             // TODO: Don't require regenerating all display lists to apply this setting
             invalidateWorld(mView);
         }
@@ -3120,7 +3128,7 @@
     int mHardwareYOffset;
 
     @Override
-    public void onPreDraw(DisplayListCanvas canvas) {
+    public void onPreDraw(RecordingCanvas canvas) {
         // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
         // can apply offsets that are not handled by anything else, resulting in underdraw as
         // the View is shifted (thus shifting the window background) exposing unpainted
@@ -3134,7 +3142,7 @@
     }
 
     @Override
-    public void onPostDraw(DisplayListCanvas canvas) {
+    public void onPostDraw(RecordingCanvas canvas) {
         drawAccessibilityFocusedDrawableIfNeeded(canvas);
         if (mUseMTRenderer) {
             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index b2dc1e9..a997302 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 
 /**
@@ -82,5 +83,5 @@
      *
      * @param canvas The canvas to draw on.
      */
-    void onPostDraw(DisplayListCanvas canvas);
+    void onPostDraw(RecordingCanvas canvas);
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 3e240cf..7f1e443 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Icon;
+import android.icu.util.ULocale;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -45,6 +46,7 @@
 import com.android.internal.util.Preconditions;
 
 import com.google.android.textclassifier.AnnotatorModel;
+import com.google.android.textclassifier.LangIdModel;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -83,6 +85,9 @@
     private static final String MODEL_FILE_REGEX = "textclassifier\\.(.*)\\.model";
     private static final String UPDATED_MODEL_FILE_PATH =
             "/data/misc/textclassifier/textclassifier.model";
+    private static final String LANG_ID_MODEL_FILE_PATH = "/etc/textclassifier/lang_id.model";
+    private static final String UPDATED_LANG_ID_MODEL_FILE_PATH =
+            "/data/misc/textclassifier/lang_id.model";
 
     private final Context mContext;
     private final TextClassifier mFallback;
@@ -94,7 +99,9 @@
     @GuardedBy("mLock") // Do not access outside this lock.
     private ModelFile mModel;
     @GuardedBy("mLock") // Do not access outside this lock.
-    private AnnotatorModel mNative;
+    private AnnotatorModel mAnnotatorImpl;
+    @GuardedBy("mLock") // Do not access outside this lock.
+    private LangIdModel mLangIdImpl;
 
     private final Object mLoggerLock = new Object();
     @GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -127,14 +134,15 @@
                     && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                 final String localesString = concatenateLocales(request.getDefaultLocales());
                 final ZonedDateTime refTime = ZonedDateTime.now();
-                final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());
+                final AnnotatorModel annotatorImpl =
+                        getAnnotatorImpl(request.getDefaultLocales());
                 final int start;
                 final int end;
                 if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
                     start = request.getStartIndex();
                     end = request.getEndIndex();
                 } else {
-                    final int[] startEnd = nativeImpl.suggestSelection(
+                    final int[] startEnd = annotatorImpl.suggestSelection(
                             string, request.getStartIndex(), request.getEndIndex(),
                             new AnnotatorModel.SelectionOptions(localesString));
                     start = startEnd[0];
@@ -145,7 +153,7 @@
                         && start <= request.getStartIndex() && end >= request.getEndIndex()) {
                     final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
                     final AnnotatorModel.ClassificationResult[] results =
-                            nativeImpl.classifyText(
+                            annotatorImpl.classifyText(
                                     string, start, end,
                                     new AnnotatorModel.ClassificationOptions(
                                             refTime.toInstant().toEpochMilli(),
@@ -187,7 +195,7 @@
                 final ZonedDateTime refTime = request.getReferenceTime() != null
                         ? request.getReferenceTime() : ZonedDateTime.now();
                 final AnnotatorModel.ClassificationResult[] results =
-                        getNative(request.getDefaultLocales())
+                        getAnnotatorImpl(request.getDefaultLocales())
                                 .classifyText(
                                         string, request.getStartIndex(), request.getEndIndex(),
                                         new AnnotatorModel.ClassificationOptions(
@@ -230,10 +238,10 @@
                     ? request.getEntityConfig().resolveEntityListModifications(
                             getEntitiesForHints(request.getEntityConfig().getHints()))
                     : mSettings.getEntityListDefault();
-            final AnnotatorModel nativeImpl =
-                    getNative(request.getDefaultLocales());
+            final AnnotatorModel annotatorImpl =
+                    getAnnotatorImpl(request.getDefaultLocales());
             final AnnotatorModel.AnnotatedSpan[] annotations =
-                    nativeImpl.annotate(
+                    annotatorImpl.annotate(
                         textString,
                         new AnnotatorModel.AnnotationOptions(
                                 refTime.toInstant().toEpochMilli(),
@@ -288,6 +296,7 @@
         }
     }
 
+    /** @inheritDoc */
     @Override
     public void onSelectionEvent(SelectionEvent event) {
         Preconditions.checkNotNull(event);
@@ -299,7 +308,29 @@
         }
     }
 
-    private AnnotatorModel getNative(LocaleList localeList)
+    /** @inheritDoc */
+    @Override
+    public TextLanguage detectLanguage(@NonNull TextLanguage.Request request) {
+        Preconditions.checkNotNull(request);
+        Utils.checkMainThread();
+        try {
+            final TextLanguage.Builder builder = new TextLanguage.Builder();
+            final LangIdModel.LanguageResult[] langResults =
+                    getLangIdImpl().detectLanguages(request.getText().toString());
+            for (int i = 0; i < langResults.length; i++) {
+                builder.putLocale(
+                        ULocale.forLanguageTag(langResults[i].getLanguage()),
+                        langResults[i].getScore());
+            }
+            return builder.build();
+        } catch (Throwable t) {
+            // Avoid throwing from this method. Log the error.
+            Log.e(LOG_TAG, "Error detecting text language.", t);
+        }
+        return mFallback.detectLanguage(request);
+    }
+
+    private AnnotatorModel getAnnotatorImpl(LocaleList localeList)
             throws FileNotFoundException {
         synchronized (mLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
@@ -307,16 +338,72 @@
             if (bestModel == null) {
                 throw new FileNotFoundException("No model for " + localeList.toLanguageTags());
             }
-            if (mNative == null || !Objects.equals(mModel, bestModel)) {
+            if (mAnnotatorImpl == null || !Objects.equals(mModel, bestModel)) {
                 Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
-                destroyNativeIfExistsLocked();
+                destroyAnnotatorImplIfExistsLocked();
                 final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
-                mNative = new AnnotatorModel(fd.getFd());
-                closeAndLogError(fd);
-                mModel = bestModel;
+                try {
+                    if (fd != null) {
+                        mAnnotatorImpl = new AnnotatorModel(fd.getFd());
+                        mModel = bestModel;
+                    }
+                } finally {
+                    maybeCloseAndLogError(fd);
+                }
             }
-            return mNative;
+            return mAnnotatorImpl;
+        }
+    }
+
+    @GuardedBy("mLock") // Do not call outside this lock.
+    private void destroyAnnotatorImplIfExistsLocked() {
+        if (mAnnotatorImpl != null) {
+            mAnnotatorImpl.close();
+            mAnnotatorImpl = null;
+        }
+    }
+
+    private LangIdModel getLangIdImpl() throws FileNotFoundException {
+        synchronized (mLock) {
+            if (mLangIdImpl == null) {
+                ParcelFileDescriptor factoryFd = null;
+                ParcelFileDescriptor updateFd = null;
+                try {
+                    int factoryVersion = -1;
+                    int updateVersion = factoryVersion;
+                    final File factoryFile = new File(LANG_ID_MODEL_FILE_PATH);
+                    if (factoryFile.exists()) {
+                        factoryFd = ParcelFileDescriptor.open(
+                                factoryFile, ParcelFileDescriptor.MODE_READ_ONLY);
+                        // TODO: Uncomment when method is implemented:
+                        // if (factoryFd != null) {
+                        //     factoryVersion = LangIdModel.getVersion(factoryFd.getFd());
+                        // }
+                    }
+                    final File updateFile = new File(UPDATED_LANG_ID_MODEL_FILE_PATH);
+                    if (updateFile.exists()) {
+                        updateFd = ParcelFileDescriptor.open(
+                                updateFile, ParcelFileDescriptor.MODE_READ_ONLY);
+                        // TODO: Uncomment when method is implemented:
+                        // if (updateFd != null) {
+                        //     updateVersion = LangIdModel.getVersion(updateFd.getFd());
+                        // }
+                    }
+
+                    if (updateVersion > factoryVersion) {
+                        mLangIdImpl = new LangIdModel(updateFd.getFd());
+                    } else if (factoryFd != null) {
+                        mLangIdImpl = new LangIdModel(factoryFd.getFd());
+                    } else {
+                        throw new FileNotFoundException("Language detection model not found");
+                    }
+                } finally {
+                    maybeCloseAndLogError(factoryFd);
+                    maybeCloseAndLogError(updateFd);
+                }
+            }
+            return mLangIdImpl;
         }
     }
 
@@ -327,14 +414,6 @@
         }
     }
 
-    @GuardedBy("mLock") // Do not call outside this lock.
-    private void destroyNativeIfExistsLocked() {
-        if (mNative != null) {
-            mNative.close();
-            mNative = null;
-        }
-    }
-
     private static String concatenateLocales(@Nullable LocaleList locales) {
         return (locales == null) ? "" : locales.toLanguageTags();
     }
@@ -407,20 +486,19 @@
                 .setText(classifiedText);
 
         final int size = classifications.length;
-        AnnotatorModel.ClassificationResult highestScoringResult = null;
-        float highestScore = Float.MIN_VALUE;
+        AnnotatorModel.ClassificationResult highestScoringResult =
+                size > 0 ? classifications[0] : null;
         for (int i = 0; i < size; i++) {
             builder.setEntityType(classifications[i].getCollection(),
                                   classifications[i].getScore());
-            if (classifications[i].getScore() > highestScore) {
+            if (classifications[i].getScore() > highestScoringResult.getScore()) {
                 highestScoringResult = classifications[i];
-                highestScore = classifications[i].getScore();
             }
         }
 
         boolean isPrimaryAction = true;
         for (LabeledIntent labeledIntent : IntentFactory.create(
-                mContext, referenceTime, highestScoringResult, classifiedText)) {
+                mContext, classifiedText, referenceTime, highestScoringResult)) {
             final RemoteAction action = labeledIntent.asRemoteAction(mContext);
             if (action == null) {
                 continue;
@@ -461,9 +539,13 @@
     }
 
     /**
-     * Closes the ParcelFileDescriptor and logs any errors that occur.
+     * Closes the ParcelFileDescriptor, if non-null, and logs any errors that occur.
      */
-    private static void closeAndLogError(ParcelFileDescriptor fd) {
+    private static void maybeCloseAndLogError(@Nullable ParcelFileDescriptor fd) {
+        if (fd == null) {
+            return;
+        }
+
         try {
             fd.close();
         } catch (IOException e) {
@@ -485,12 +567,17 @@
         /** Returns null if the path did not point to a compatible model. */
         static @Nullable ModelFile fromPath(String path) {
             final File file = new File(path);
+            if (!file.exists()) {
+                return null;
+            }
+            ParcelFileDescriptor modelFd = null;
             try {
-                final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
-                        file, ParcelFileDescriptor.MODE_READ_ONLY);
+                modelFd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+                if (modelFd == null) {
+                    return null;
+                }
                 final int version = AnnotatorModel.getVersion(modelFd.getFd());
-                final String supportedLocalesStr =
-                        AnnotatorModel.getLocales(modelFd.getFd());
+                final String supportedLocalesStr = AnnotatorModel.getLocales(modelFd.getFd());
                 if (supportedLocalesStr.isEmpty()) {
                     Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
                     return null;
@@ -500,12 +587,13 @@
                 for (String langTag : supportedLocalesStr.split(",")) {
                     supportedLocales.add(Locale.forLanguageTag(langTag));
                 }
-                closeAndLogError(modelFd);
                 return new ModelFile(path, file.getName(), version, supportedLocales,
                                      languageIndependent);
             } catch (FileNotFoundException e) {
                 Log.e(DEFAULT_LOG_TAG, "Failed to peek " + file.getAbsolutePath(), e);
                 return null;
+            } finally {
+                maybeCloseAndLogError(modelFd);
             }
         }
 
@@ -557,12 +645,12 @@
         public boolean equals(Object other) {
             if (this == other) {
                 return true;
-            } else if (other == null || !ModelFile.class.isAssignableFrom(other.getClass())) {
-                return false;
-            } else {
+            }
+            if (other instanceof ModelFile) {
                 final ModelFile otherModel = (ModelFile) other;
                 return mPath.equals(otherModel.mPath);
             }
+            return false;
         }
 
         @Override
@@ -677,10 +765,12 @@
         @NonNull
         public static List<LabeledIntent> create(
                 Context context,
+                String text,
                 @Nullable Instant referenceTime,
-                AnnotatorModel.ClassificationResult classification,
-                String text) {
-            final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
+                @Nullable AnnotatorModel.ClassificationResult classification) {
+            final String type = classification != null
+                    ? classification.getCollection().trim().toLowerCase(Locale.ENGLISH)
+                    : null;
             text = text.trim();
             switch (type) {
                 case TextClassifier.TYPE_EMAIL:
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index ba66571..6ab7f66 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -27,11 +27,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.SparseArray;
-import android.view.DisplayListCanvas;
 import android.view.View;
 import android.view.ViewRootImpl;
 
@@ -107,12 +107,12 @@
      * @throws IllegalArgumentException if the canvas is not hardware accelerated
      */
     public void callDrawGlFunction(Canvas canvas, long nativeDrawGLFunctor) {
-        if (!(canvas instanceof DisplayListCanvas)) {
+        if (!(canvas instanceof RecordingCanvas)) {
             // Canvas#isHardwareAccelerated() is only true for subclasses of HardwareCanvas.
             throw new IllegalArgumentException(canvas.getClass().getName()
                     + " is not a DisplayList canvas");
         }
-        ((DisplayListCanvas) canvas).drawGLFunctor2(nativeDrawGLFunctor, null);
+        ((RecordingCanvas) canvas).drawGLFunctor2(nativeDrawGLFunctor, null);
     }
 
     /**
@@ -129,12 +129,12 @@
      */
     public void callDrawGlFunction(@NonNull Canvas canvas, long nativeDrawGLFunctor,
             @Nullable Runnable releasedRunnable) {
-        if (!(canvas instanceof DisplayListCanvas)) {
+        if (!(canvas instanceof RecordingCanvas)) {
             // Canvas#isHardwareAccelerated() is only true for subclasses of HardwareCanvas.
             throw new IllegalArgumentException(canvas.getClass().getName()
                     + " is not a DisplayList canvas");
         }
-        ((DisplayListCanvas) canvas).drawGLFunctor2(nativeDrawGLFunctor, releasedRunnable);
+        ((RecordingCanvas) canvas).drawGLFunctor2(nativeDrawGLFunctor, releasedRunnable);
     }
 
     /**
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 8027dd7..48c164f 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -42,8 +42,10 @@
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.RenderNode;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -83,7 +85,6 @@
 import android.view.ActionMode.Callback;
 import android.view.ContextMenu;
 import android.view.ContextThemeWrapper;
-import android.view.DisplayListCanvas;
 import android.view.DragAndDropPermissions;
 import android.view.DragEvent;
 import android.view.Gravity;
@@ -93,7 +94,6 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
-import android.view.RenderNode;
 import android.view.SubMenu;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
@@ -1941,18 +1941,18 @@
 
             // Rebuild display list if it is invalid
             if (blockDisplayListIsInvalid) {
-                final DisplayListCanvas displayListCanvas = blockDisplayList.start(
+                final RecordingCanvas recordingCanvas = blockDisplayList.start(
                         right - left, bottom - top);
                 try {
                     // drawText is always relative to TextView's origin, this translation
                     // brings this range of text back to the top left corner of the viewport
-                    displayListCanvas.translate(-left, -top);
-                    layout.drawText(displayListCanvas, blockBeginLine, blockEndLine);
+                    recordingCanvas.translate(-left, -top);
+                    layout.drawText(recordingCanvas, blockBeginLine, blockEndLine);
                     mTextRenderNodes[blockIndex].isDirty = false;
                     // No need to untranslate, previous context is popped after
                     // drawDisplayList
                 } finally {
-                    blockDisplayList.end(displayListCanvas);
+                    blockDisplayList.end(recordingCanvas);
                     // Same as drawDisplayList below, handled by our TextView's parent
                     blockDisplayList.setClipToBounds(false);
                 }
@@ -1962,7 +1962,7 @@
             blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
             mTextRenderNodes[blockIndex].needsToBeShifted = false;
         }
-        ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList);
+        ((RecordingCanvas) canvas).drawRenderNode(blockDisplayList);
         return startIndexToFindAvailableRenderNode;
     }
 
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 16ddd0f..6a3fc0f 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -33,15 +33,15 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
-import android.view.DisplayListCanvas;
 import android.view.PixelCopy;
-import android.view.RenderNode;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
@@ -704,7 +704,7 @@
                     cornerRadius
             );
 
-            final DisplayListCanvas canvas = mRenderer.getRootNode().start(width, height);
+            final RecordingCanvas canvas = mRenderer.getRootNode().start(width, height);
             try {
                 canvas.insertReorderBarrier();
                 canvas.drawRenderNode(mBitmapRenderNode);
@@ -736,7 +736,7 @@
             bitmapRenderNode.setClipToOutline(true);
 
             // Create a dummy draw, which will be replaced later with real drawing.
-            final DisplayListCanvas canvas = bitmapRenderNode.start(mContentWidth, mContentHeight);
+            final RecordingCanvas canvas = bitmapRenderNode.start(mContentWidth, mContentHeight);
             try {
                 canvas.drawColor(0xFF00FF00);
             } finally {
@@ -817,7 +817,7 @@
                     return;
                 }
 
-                final DisplayListCanvas canvas =
+                final RecordingCanvas canvas =
                         mBitmapRenderNode.start(mContentWidth, mContentHeight);
                 try {
                     canvas.drawColor(Color.WHITE);
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index b8a2dff..c0c689c 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -52,4 +52,6 @@
 
     /** For both ...Intent and ...Service based usage */
     boolean isRecognitionActive(in ParcelUuid parcelUuid);
+
+    SoundTrigger.RecognitionEvent getModelState(in ParcelUuid parcelUuid);
 }
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 8dc97fe..2b661c2 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -49,6 +49,7 @@
     private final int mEntriesSizeCap;
     private int mSamplingInterval;
     private CachedDeviceState.Readonly mDeviceState;
+    private long mStartTime = System.currentTimeMillis();
 
     public LooperStats(int samplingInterval, int entriesSizeCap) {
         this.mSamplingInterval = samplingInterval;
@@ -144,6 +145,11 @@
         return exportedEntries;
     }
 
+    /** Returns a timestamp indicating when the statistics were last reset. */
+    public long getStartTimeMillis() {
+        return mStartTime;
+    }
+
     private void maybeAddSpecialEntry(List<ExportedEntry> exportedEntries, Entry specialEntry) {
         synchronized (specialEntry) {
             if (specialEntry.messageCount > 0 || specialEntry.exceptionCount > 0) {
@@ -163,6 +169,7 @@
         synchronized (mOverflowEntry) {
             mOverflowEntry.reset();
         }
+        mStartTime = System.currentTimeMillis();
     }
 
     public void setSamplingInterval(int samplingInterval) {
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index a70209c..f14007b 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -16,13 +16,13 @@
 
 package com.android.internal.policy;
 
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Looper;
 import android.view.Choreographer;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 import android.view.ThreadedRenderer;
 
 /**
@@ -339,7 +339,7 @@
         mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height);
 
         // Draw the caption and content backdrops in to our render node.
-        DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height);
+        RecordingCanvas canvas = mFrameAndBackdropNode.start(width, height);
         final Drawable drawable = mUserCaptionBackgroundDrawable != null
                 ? mUserCaptionBackgroundDrawable : mCaptionBackgroundDrawable;
 
@@ -368,7 +368,7 @@
         if (mSystemBarBackgroundNode == null) {
             return;
         }
-        DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height);
+        RecordingCanvas canvas = mSystemBarBackgroundNode.start(width, height);
         mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
         final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
         if (mStatusBarColor != null) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 4697266..94140ab 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -16,76 +16,6 @@
 
 package com.android.internal.policy;
 
-import android.annotation.Nullable;
-import android.annotation.TestApi;
-import android.app.WindowConfiguration;
-import android.graphics.Outline;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.util.Pair;
-import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.internal.R;
-import com.android.internal.policy.PhoneWindow.PanelFeatureState;
-import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
-import com.android.internal.view.FloatingActionMode;
-import com.android.internal.view.RootViewSurfaceTaker;
-import com.android.internal.view.StandaloneActionMode;
-import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.MenuHelper;
-import com.android.internal.widget.ActionBarContextView;
-import com.android.internal.widget.BackgroundFallback;
-import com.android.internal.widget.DecorCaptionView;
-import com.android.internal.widget.FloatingToolbar;
-
-import java.util.List;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.Shader;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.DisplayListCanvas;
-import android.view.Gravity;
-import android.view.InputQueue;
-import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.ThreadedRenderer;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
-import android.view.ViewTreeObserver;
-import android.view.Window;
-import android.view.WindowCallbacks;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-import android.widget.PopupWindow;
-
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -108,8 +38,79 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
+
 import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.WindowConfiguration;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Shader;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Pair;
+import android.util.TypedValue;
+import android.view.ActionMode;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.InputQueue;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.ThreadedRenderer;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.ViewStub;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+import android.view.WindowCallbacks;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.PopupWindow;
+
+import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow.PanelFeatureState;
+import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
+import com.android.internal.view.FloatingActionMode;
+import com.android.internal.view.RootViewSurfaceTaker;
+import com.android.internal.view.StandaloneActionMode;
+import com.android.internal.view.menu.ContextMenuBuilder;
+import com.android.internal.view.menu.MenuHelper;
+import com.android.internal.widget.ActionBarContextView;
+import com.android.internal.widget.BackgroundFallback;
+import com.android.internal.widget.DecorCaptionView;
+import com.android.internal.widget.FloatingToolbar;
+
+import java.util.List;
+
 /** @hide */
 public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
     private static final String TAG = "DecorView";
@@ -2134,7 +2135,7 @@
     }
 
     @Override
-    public void onPostDraw(DisplayListCanvas canvas) {
+    public void onPostDraw(RecordingCanvas canvas) {
         drawResizingShadowIfNeeded(canvas);
     }
 
@@ -2152,7 +2153,7 @@
                 new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
     }
 
-    private void drawResizingShadowIfNeeded(DisplayListCanvas canvas) {
+    private void drawResizingShadowIfNeeded(RecordingCanvas canvas) {
         if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
                 || mWindow.isTranslucent()
                 || mWindow.isShowingWallpaper()) {
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 367b713..794238a 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -29,10 +29,8 @@
  * {@hide}
  */
 oneway interface IInputMethodSession {
-    void finishInput();
-
     void updateExtractedText(int token, in ExtractedText text);
-    
+
     void updateSelection(int oldSelStart, int oldSelEnd,
             int newSelStart, int newSelEnd,
             int candidatesStart, int candidatesEnd);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 9263b57..b799728 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -24,23 +24,21 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
-import android.graphics.drawable.Drawable;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.DisplayListCanvas;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.RenderNodeAnimator;
@@ -71,6 +69,7 @@
     private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
 
     private static final boolean PROFILE_DRAWING = false;
+    private static final float LINE_FADE_ALPHA_MULTIPLIER = 3.5f;
     private final CellState[][] mCellStates;
 
     private final int mDotSize;
@@ -1131,8 +1130,8 @@
                     drawCellDrawable(canvas, i, j, cellState.radius, drawLookup[i][j]);
                 } else {
                     if (isHardwareAccelerated() && cellState.hwAnimating) {
-                        DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
-                        displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+                        RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+                        recordingCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
                                 cellState.hwRadius, cellState.hwPaint);
                     } else {
                         drawCircle(canvas, (int) centerX, (int) centerY + translationY,
@@ -1172,9 +1171,9 @@
                 float centerX = getCenterXForColumn(cell.column);
                 float centerY = getCenterYForRow(cell.row);
                 if (i != 0) {
-                   // Set this line segment to slowly fade over the next second.
+                   // Set this line segment to fade away animated.
                    int lineFadeVal = (int) Math.min((elapsedRealtime -
-                           mLineFadeStart[i])/2f, 255f);
+                           mLineFadeStart[i]) * LINE_FADE_ALPHA_MULTIPLIER, 255f);
 
                     CellState state = mCellStates[cell.row][cell.column];
                     currentPath.rewind();
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 9dbb8d7..b417a56 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -788,6 +788,63 @@
     return status;
 }
 
+static jobject
+android_hardware_SoundTrigger_getModelState(JNIEnv *env, jobject thiz,
+                                            jint jHandle)
+{
+    ALOGV("getModelState");
+    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+    if (module == NULL) {
+        return NULL;
+    }
+    sp<IMemory> memory;
+    jint status = module->getModelState(jHandle, memory);
+    if (status != 0 || memory == NULL) {
+        ALOGW("getModelState, failed to get model state, status: %d", status);
+        return NULL;
+    }
+    struct sound_trigger_recognition_event* event =
+        (struct sound_trigger_recognition_event *)memory->pointer();
+    if (event == NULL) {
+        return NULL;
+    }
+    if (event->type != SOUND_MODEL_TYPE_GENERIC) {
+        ALOGW("getModelState, unsupported model type: %d", event->type);
+        return NULL;
+    }
+
+    jbyteArray jData = NULL;
+    if (event->data_size) {
+        jData = env->NewByteArray(event->data_size);
+        jbyte *nData = env->GetByteArrayElements(jData, NULL);
+        memcpy(nData, (char *)event + event->data_offset, event->data_size);
+        env->ReleaseByteArrayElements(jData, nData, 0);
+    }
+
+    jobject jAudioFormat = NULL;
+    if (event->trigger_in_data || event->capture_available) {
+        jAudioFormat = env->NewObject(gAudioFormatClass,
+                                      gAudioFormatCstor,
+                                      audioFormatFromNative(event->audio_config.format),
+                                      event->audio_config.sample_rate,
+                                      inChannelMaskFromNative(event->audio_config.channel_mask));
+
+    }
+    jobject jEvent = NULL;
+    jEvent = env->NewObject(gGenericRecognitionEventClass, gGenericRecognitionEventCstor,
+                            event->status, event->model, event->capture_available,
+                            event->capture_session, event->capture_delay_ms,
+                            event->capture_preamble_ms, event->trigger_in_data,
+                            jAudioFormat, jData);
+    if (jAudioFormat != NULL) {
+        env->DeleteLocalRef(jAudioFormat);
+    }
+    if (jData != NULL) {
+        env->DeleteLocalRef(jData);
+    }
+    return jEvent;
+}
+
 static const JNINativeMethod gMethods[] = {
     {"listModules",
         "(Ljava/util/ArrayList;)I",
@@ -817,6 +874,9 @@
     {"stopRecognition",
         "(I)I",
         (void *)android_hardware_SoundTrigger_stopRecognition},
+    {"getModelState",
+        "(I)Landroid/hardware/soundtrigger/SoundTrigger$RecognitionEvent;",
+        (void *)android_hardware_SoundTrigger_getModelState},
 };
 
 int register_android_hardware_SoundTrigger(JNIEnv *env)
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index da4cdb6..83a8c2e 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -127,10 +127,9 @@
     case AUDIO_FORMAT_DOLBY_TRUEHD:
         return ENCODING_DOLBY_TRUEHD;
     case AUDIO_FORMAT_AAC_ELD:
-            return ENCODING_AAC_ELD;
-    // FIXME needs addition of AUDIO_FORMAT_AAC_XHE
-    //case AUDIO_FORMAT_AAC_XHE:
-    //    return ENCODING_AAC_XHE;
+        return ENCODING_AAC_ELD;
+    case AUDIO_FORMAT_AAC_XHE:
+        return ENCODING_AAC_XHE;
     case AUDIO_FORMAT_AC4:
         return ENCODING_AC4;
     case AUDIO_FORMAT_E_AC3_JOC:
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 6456fe6..bf22dd2 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -29,6 +29,7 @@
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
 
+#include <android-base/macros.h>
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
 
@@ -134,41 +135,53 @@
         callbackInfo->busy = true;
     }
 
+    // used as default argument when event callback doesn't have any, or number of
+    // frames for EVENT_CAN_WRITE_MORE_DATA
+    int arg = 0;
+    bool postEvent = false;
     switch (event) {
     // Offload only events
-    case AudioTrack::EVENT_STREAM_END:
-    case AudioTrack::EVENT_MORE_DATA:
-    // a.k.a. tear down
-    case AudioTrack::EVENT_NEW_IAUDIOTRACK:
+    case AudioTrack::EVENT_CAN_WRITE_MORE_DATA:
+        // this event will read the info return parameter of the callback:
+        // for JNI offload, use the returned size to indicate:
+        // 1/ no data is returned through callback, as it's all done through write()
+        // 2/ do not wait as AudioTrack does when it receives 0 bytes
         if (callbackInfo->isOffload) {
-            JNIEnv *env = AndroidRuntime::getJNIEnv();
-            if (user != NULL && env != NULL) {
-                env->CallStaticVoidMethod(
-                        callbackInfo->audioTrack_class,
-                        javaAudioTrackFields.postNativeEventInJava,
-                        callbackInfo->audioTrack_ref, event, 0,0, NULL);
-                if (env->ExceptionCheck()) {
-                    env->ExceptionDescribe();
-                    env->ExceptionClear();
-                }
-            }
-        } break;
+            AudioTrack::Buffer* pBuffer = (AudioTrack::Buffer*) info;
+            const size_t availableForWrite = pBuffer->size;
+            arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
+            pBuffer->size = 0;
+        }
+        FALLTHROUGH_INTENDED;
+    case AudioTrack::EVENT_STREAM_END:
+    case AudioTrack::EVENT_NEW_IAUDIOTRACK: // a.k.a. tear down
+        if (callbackInfo->isOffload) {
+            postEvent = true;
+        }
+        break;
 
     // PCM and offload events
     case AudioTrack::EVENT_MARKER:
-    case AudioTrack::EVENT_NEW_POS: {
+    case AudioTrack::EVENT_NEW_POS:
+        postEvent = true;
+        break;
+    default:
+        // event will not be posted
+        break;
+    }
+
+    if (postEvent) {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user != NULL && env != NULL) {
+        if (env != NULL) {
             env->CallStaticVoidMethod(
                     callbackInfo->audioTrack_class,
                     javaAudioTrackFields.postNativeEventInJava,
-                    callbackInfo->audioTrack_ref, event, 0,0, NULL);
+                    callbackInfo->audioTrack_ref, event, arg, 0, NULL);
             if (env->ExceptionCheck()) {
                 env->ExceptionDescribe();
                 env->ExceptionClear();
             }
         }
-        } break;
     }
 
     {
@@ -215,10 +228,10 @@
         jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
         jlong nativeAudioTrack, jboolean offload) {
 
-    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
-        "nativeAudioTrack=0x%" PRIX64,
+    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
+        " nativeAudioTrack=0x%" PRIX64 ", offload=%d",
         jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
-        nativeAudioTrack);
+        nativeAudioTrack, offload);
 
     sp<AudioTrack> lpTrack = 0;
 
@@ -318,7 +331,7 @@
         lpJniStorage->mCallbackData.busy = false;
 
         audio_offload_info_t offloadInfo;
-        if (offload) {
+        if (offload == JNI_TRUE) {
             offloadInfo = AUDIO_INFO_INITIALIZER;
             offloadInfo.format = format;
             offloadInfo.sample_rate = sampleRateInHertz;
@@ -331,23 +344,23 @@
         status_t status = NO_ERROR;
         switch (memoryMode) {
         case MODE_STREAM:
-
             status = lpTrack->set(
                     AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
                     sampleRateInHertz,
                     format,// word length, PCM
                     nativeChannelMask,
-                    frameCount,
-                    AUDIO_OUTPUT_FLAG_NONE,
+                    offload ? 0 : frameCount,
+                    offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE,
                     audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
                     0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
                     0,// shared mem
                     true,// thread can call Java
                     sessionId,// audio session ID
-                    AudioTrack::TRANSFER_SYNC,
+                    offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
                     offload ? &offloadInfo : NULL,
                     -1, -1,                       // default uid, pid values
                     paa);
+
             break;
 
         case MODE_STATIC:
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
index 4a30bab..b52f137 100644
--- a/core/jni/android_opengl_EGL15.cpp
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -456,67 +456,9 @@
 static jobject
 android_eglCreatePlatformPixmapSurface
   (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) {
-    jint _exception = 0;
-    const char * _exceptionType = NULL;
-    const char * _exceptionMessage = NULL;
-    jarray _array = (jarray) 0;
-    jint _bufferOffset = (jint) 0;
-    EGLSurface _returnValue = (EGLSurface) 0;
-    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
-    EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
-    jint _native_pixmapRemaining;
-    void *native_pixmap = (void *) 0;
-    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
-    jint _attrib_listRemaining;
-    EGLAttrib *attrib_list = (EGLAttrib *) 0;
-
-    if (!native_pixmap_buf) {
-        _exception = 1;
-        _exceptionType = "java/lang/IllegalArgumentException";
-        _exceptionMessage = "native_pixmap == null";
-        goto exit;
-    }
-    native_pixmap = (void *)getPointer(_env, native_pixmap_buf, (jarray*)&_array, &_native_pixmapRemaining, &_bufferOffset);
-    if (!attrib_list_ref) {
-        _exception = 1;
-        _exceptionType = "java/lang/IllegalArgumentException";
-        _exceptionMessage = "attrib_list == null";
-        goto exit;
-    }
-    if (offset < 0) {
-        _exception = 1;
-        _exceptionType = "java/lang/IllegalArgumentException";
-        _exceptionMessage = "offset < 0";
-        goto exit;
-    }
-    _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
-    attrib_list_base = (EGLAttrib *)
-        _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
-    attrib_list = attrib_list_base + offset;
-
-    if (native_pixmap == NULL) {
-        char * _native_pixmapBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
-        native_pixmap = (void *) (_native_pixmapBase + _bufferOffset);
-    }
-    _returnValue = eglCreatePlatformPixmapSurface(
-        (EGLDisplay)dpy_native,
-        (EGLConfig)config_native,
-        (void *)native_pixmap,
-        (EGLAttrib *)attrib_list
-    );
-
-exit:
-    if (attrib_list_base) {
-        _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
-            JNI_ABORT);
-    }
-    if (_array) {
-        releasePointer(_env, _array, native_pixmap, _exception ? JNI_FALSE : JNI_TRUE);
-    }
-    if (_exception) {
-        jniThrowException(_env, _exceptionType, _exceptionMessage);
-    }
-    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+    jniThrowException(_env, "java/lang/UnsupportedOperationException",
+        "eglCreatePlatformPixmapSurface");
+    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
 }
 
 /* EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags ) */
@@ -535,6 +477,71 @@
     return (jboolean)_returnValue;
 }
 
+/* EGLImage eglCreateImage ( EGLDisplay dpy, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreateImage
+  (JNIEnv *_env, jobject _this, jobject dpy, jobject context, jint target, jlong buffer, jlongArray attrib_list_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLImage _returnValue = (EGLImage) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLContext context_native = (EGLContext) fromEGLHandle(_env, eglcontextGetHandleID, context);
+    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jint _remaining;
+    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+    if (!attrib_list_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+    attrib_list_base = (EGLAttrib *)
+        _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+    attrib_list = attrib_list_base + offset;
+
+    _returnValue = eglCreateImage(
+        (EGLDisplay)dpy_native,
+        (EGLContext)context_native,
+        (EGLenum)target,
+        (EGLClientBuffer)buffer,
+        (EGLAttrib *)attrib_list
+    );
+
+exit:
+    if (attrib_list_base) {
+        _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return toEGLHandle(_env, eglimageClass, eglimageConstructor, _returnValue);
+}
+
+/* EGLBoolean eglDestroyImage ( EGLDisplay dpy, EGLImage image ) */
+static jboolean
+android_eglDestroyImage
+  (JNIEnv *_env, jobject _this, jobject dpy, jobject image) {
+    EGLBoolean _returnValue = (EGLBoolean) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLImage image_native = (EGLImage) fromEGLHandle(_env, eglimageGetHandleID, image);
+
+    _returnValue = eglDestroyImage(
+        (EGLDisplay)dpy_native,
+        (EGLImage)image_native
+    );
+    return (jboolean)_returnValue;
+}
+
 static const char *classPathName = "android/opengl/EGL15";
 
 static const JNINativeMethod methods[] = {
@@ -547,6 +554,8 @@
 {"eglCreatePlatformWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformWindowSurface },
 {"eglCreatePlatformPixmapSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformPixmapSurface },
 {"eglWaitSync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I)Z", (void *) android_eglWaitSync },
+{"eglCreateImage", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLContext;IJ[JI)Landroid/opengl/EGLImage;", (void *) android_eglCreateImage },
+{"eglDestroyImage", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLImage;)Z", (void *) android_eglDestroyImage },
 };
 
 int register_android_opengl_jni_EGL15(JNIEnv *_env)
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d023d22..ec98080 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -904,6 +904,21 @@
     return IPCThreadState::self()->getStrictModePolicy();
 }
 
+static jint android_os_Binder_setThreadWorkSource(jint workSource)
+{
+    return IPCThreadState::self()->setWorkSource(workSource);
+}
+
+static jint android_os_Binder_getThreadWorkSource()
+{
+    return IPCThreadState::self()->getWorkSource();
+}
+
+static jint android_os_Binder_clearThreadWorkSource()
+{
+    return IPCThreadState::self()->clearWorkSource();
+}
+
 static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
 {
     IPCThreadState::self()->flushCommands();
@@ -941,6 +956,12 @@
     { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
     { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
     { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
+    // @CriticalNative
+    { "setThreadWorkSource", "(I)I", (void*)android_os_Binder_setThreadWorkSource },
+    // @CriticalNative
+    { "getThreadWorkSource", "()I", (void*)android_os_Binder_getThreadWorkSource },
+    // @CriticalNative
+    { "clearThreadWorkSource", "()I", (void*)android_os_Binder_clearThreadWorkSource },
     { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
     { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
     { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 62aa1f38..4c7defb 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -51,6 +51,8 @@
 
 static const bool kDebugPolicy = false;
 static const bool kDebugProc = false;
+// When reading `proc` files, how many bytes to read at a time
+static const int kReadSize = 4096;
 
 #if GUARD_THREAD_PRIORITY
 Mutex gKeyCreateMutex;
@@ -1034,21 +1036,35 @@
     }
     env->ReleaseStringUTFChars(file, file8);
 
-    char buffer[256];
-    const int len = read(fd, buffer, sizeof(buffer)-1);
+    std::vector<char> fileBuffer(kReadSize);
+    int numBytesRead = 0;
+    while (true) {
+        // Resize buffer to make space for contents. This might be more than we need, but once we've
+        // read we resize back down
+        fileBuffer.resize(numBytesRead + kReadSize, 0);
+        // Read in contents
+        int len = TEMP_FAILURE_RETRY(read(fd, fileBuffer.data() + numBytesRead, kReadSize));
+        numBytesRead += len;
+        if (len < 0) {
+            // If `len` is negative, an error occurred on read
+            if (kDebugProc) {
+                ALOGW("Unable to open process file: %s fd=%d\n", file8, fd);
+            }
+            close(fd);
+            return JNI_FALSE;
+        } else if (len == 0) {
+            // If nothing read, we're done
+            break;
+        }
+    }
+    // Resize back down to the amount we read
+    fileBuffer.resize(numBytesRead);
+    // Terminate buffer with null byte
+    fileBuffer.push_back('\0');
     close(fd);
 
-    if (len < 0) {
-        if (kDebugProc) {
-            ALOGW("Unable to open process file: %s fd=%d\n", file8, fd);
-        }
-        return JNI_FALSE;
-    }
-    buffer[len] = 0;
-
-    return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len,
+    return android_os_Process_parseProcLineArray(env, clazz, fileBuffer.data(), 0, numBytesRead,
             format, outStrings, outLongs, outFloats);
-
 }
 
 void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 4fdd2bc..8998cd7 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -183,7 +183,7 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/DisplayListCanvas";
+const char* const kClassPathName = "android/graphics/RecordingCanvas";
 
 static JNINativeMethod gMethods[] = {
 
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 63b0046..bb71a5d 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -576,7 +576,7 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/RenderNode";
+const char* const kClassPathName = "android/graphics/RenderNode";
 
 static const JNINativeMethod gMethods[] = {
 // ----------------------------------------------------------------------------
@@ -588,7 +588,7 @@
     { "nGetDebugSize",         "(J)I",    (void*) android_view_RenderNode_getDebugSize },
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
-    { "nRequestPositionUpdates",   "(JLandroid/view/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },
+    { "nRequestPositionUpdates",   "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },
     { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
 
 
@@ -677,7 +677,7 @@
 };
 
 int register_android_view_RenderNode(JNIEnv* env) {
-    jclass clazz = FindClassOrDie(env, "android/view/RenderNode$PositionUpdateListener");
+    jclass clazz = FindClassOrDie(env, "android/graphics/RenderNode$PositionUpdateListener");
     gPositionListener_PositionChangedMethod = GetMethodIDOrDie(env, clazz,
             "positionChanged", "(JIIII)V");
     gPositionListener_PositionLostMethod = GetMethodIDOrDie(env, clazz,
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 2e1e130..4eda3ab 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -166,8 +166,10 @@
     }
     Rect sourceCrop = rectFromObj(env, sourceCropObj);
     sp<GraphicBuffer> buffer;
-    status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
-            useIdentityTransform, rotation, &buffer);
+    status_t res = ScreenshotClient::capture(displayToken, ui::Dataspace::V0_SRGB,
+                                             ui::PixelFormat::RGBA_8888,
+                                             sourceCrop, width, height,
+                                             useIdentityTransform, rotation, &buffer);
     if (res != NO_ERROR) {
         return NULL;
     }
@@ -195,7 +197,9 @@
     }
 
     sp<GraphicBuffer> buffer;
-    status_t res = ScreenshotClient::captureChildLayers(layerHandle, sourceCrop, frameScale, &buffer);
+    status_t res = ScreenshotClient::captureChildLayers(layerHandle, ui::Dataspace::V0_SRGB,
+                                                        ui::PixelFormat::RGBA_8888, sourceCrop,
+                                                        frameScale, &buffer);
     if (res != NO_ERROR) {
         return NULL;
     }
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
new file mode 100644
index 0000000..2797550
--- /dev/null
+++ b/core/proto/android/app/settings_enums.proto
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+
+package android.app.settings;
+option java_multiple_files = true;
+
+/**
+ * The action performed in this event
+ */
+enum Action {
+    ACTION_UNKNOWN = 0;
+    PAGE_VISIBLE = 1;
+    PAGE_HIDE = 2;
+    PREF_CHANGE = 3;
+}
+
+/**
+ * Id for Settings pages. Each page must have its own unique Id.
+ */
+enum PageId {
+  // Unknown page. Should not be used in production code.
+  PAGE_UNKNOWN = 0;
+
+  // OPEN: Settings homepage
+  SETTINGS_HOMEPAGE = 1502;
+
+  // OPEN: Settings > System > Input & Gesture > Wake screen
+  SETTINGS_GESTURE_WAKE_SCREEN = 1570;
+
+  // OPEN: Settings > Network & internet > Mobile network
+  MOBILE_NETWORK = 1571;
+
+  // OPEN: Settings > Network & internet > Mobile network > Choose network
+  MOBILE_NETWORK_SELECT = 1581;
+
+  // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog
+  MOBILE_DATA_DIALOG = 1582;
+
+  // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog
+  MOBILE_ROAMING_DIALOG = 1583;
+
+  // Settings > Display > Lock screen display > On lock screen
+  LOCK_SCREEN_NOTIFICATION_CONTENT = 1584;
+}
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1ae5f03..374c7ea 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4342,7 +4342,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                android:theme="@style/Theme.Dialog.Confirmation"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
@@ -4363,7 +4363,7 @@
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
                 android:excludeFromRecents="true"
                 android:process=":ui"
-                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert">
+                android:theme="@style/Theme.Dialog.Confirmation">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -4371,24 +4371,24 @@
         </activity>
 
         <activity android:name="com.android.internal.app.SuspendedAppActivity"
-                  android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true"
                   android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                android:theme="@style/Theme.Dialog.Confirmation"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
 
         <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
-                  android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true">
         </activity>
 
         <activity android:name="com.android.internal.app.HarmfulAppWarningActivity"
-                  android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true"
                   android:process=":ui"
                   android:label="@string/harmful_app_warning_title"
diff --git a/core/res/res/layout/harmful_app_warning_dialog.xml b/core/res/res/layout/harmful_app_warning_dialog.xml
index d41691f..62ca7a6 100644
--- a/core/res/res/layout/harmful_app_warning_dialog.xml
+++ b/core/res/res/layout/harmful_app_warning_dialog.xml
@@ -49,7 +49,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:gravity="center_vertical"
-                    android:textColor="@color/primary_text_material_light"
+                    android:textColor="?attr/textColorPrimary"
                     android:textSize="@dimen/text_size_subhead_material"
                     android:paddingLeft="@dimen/harmful_app_icon_name_padding">
             </TextView>
@@ -65,4 +65,4 @@
                 android:lineSpacingMultiplier="@dimen/harmful_app_message_line_spacing_modifier"
                 android:textSize="@dimen/text_size_body_1_material"/>
     </LinearLayout>
-</ScrollView>
\ No newline at end of file
+</ScrollView>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index 48b59c7..176e89e 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -15,6 +15,7 @@
 -->
 <resources>
     <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Dialog.Confirmation" parent="Theme.Leanback.Dialog.Confirmation" />
     <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
     <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
     <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 32cf2e8..a25c998 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1141,6 +1141,15 @@
 
         <!-- Alpha value of the spot shadow projected by elevated views, between 0 and 1. -->
         <attr name="spotShadowAlpha" format="float" />
+
+        <!-- <p>Whether or not the force dark feature is allowed to be applied to this theme.
+             <p>Setting this to false will disable the auto-dark feature on everything this
+             theme is applied to along with anything drawn by any children of views using
+             this theme.
+             <p>Setting this to true will allow this view to be automatically made dark, however
+             a value of 'true' will not override any 'false' value in its parent chain nor will
+             it prevent any 'false' in any of its children. -->
+        <attr name="forceDarkAllowed" format="boolean" />
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -3116,8 +3125,13 @@
              {@link android.R.attr#ambientShadowAlpha} theme attribute. -->
         <attr name="outlineAmbientShadowColor" format="color" />
 
-        <!-- Whether to allow the rendering system to force this View to render as light-on-dark. -->
-        <attr name="allowForceDark" format="boolean" />
+        <!-- <p>Whether or not the force dark feature is allowed to be applied to this View.
+             <p>Setting this to false will disable the auto-dark feature on this View draws
+             including any descendants.
+             <p>Setting this to true will allow this view to be automatically made dark, however
+             a value of 'true' will not override any 'false' value in its parent chain nor will
+             it prevent any 'false' in any of its children. -->
+        <attr name="forceDarkAllowed" format="boolean" />
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fd688a7..b790829 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2908,7 +2908,7 @@
         <public name="opticalInsetTop" />
         <public name="opticalInsetRight" />
         <public name="opticalInsetBottom" />
-        <public name="allowForceDark" />
+        <public name="forceDarkAllowed" />
         <public name="supportsAmbientMode" />
         <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
         <public name="usesNonSdkApi" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index a7530ce..ad38f3d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -880,6 +880,9 @@
         <item name="windowActivityTransitions">false</item>
     </style>
 
+    <!-- @hide Special theme for the default system Activity-based Alert dialogs. -->
+    <style name="Theme.Dialog.Confirmation" parent="Theme.DeviceDefault.Light.Dialog.Alert" />
+
     <!-- Theme for a window that looks like a toast. -->
     <style name="Theme.Toast" parent="Theme.DeviceDefault.Dialog">
         <item name="windowBackground">?attr/toastFrameBackground</item>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index f71df9f..a80725c 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -130,4 +130,7 @@
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
       </style>
 
+    <!-- @hide Special theme for the default system Activity-based Alert dialogs. -->
+    <style name="Theme.Leanback.Dialog.Confirmation" parent="Theme.DeviceDefault.Dialog.Alert" />
+
 </resources>
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
new file mode 100644
index 0000000..1beb598
--- /dev/null
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class BinderTest extends TestCase {
+
+    @SmallTest
+    public void testSetWorkSource() throws Exception {
+        Binder.setThreadWorkSource(100);
+        assertEquals(100, Binder.getThreadWorkSource());
+    }
+
+    @SmallTest
+    public void testClearWorkSource() throws Exception {
+        Binder.setThreadWorkSource(100);
+        Binder.clearThreadWorkSource();
+        assertEquals(-1, Binder.getThreadWorkSource());
+    }
+}
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 7360e9f..45a5010 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -402,11 +402,10 @@
         state.assertEquals("|");
 
         // Emoji modifier + ZERO WIDTH JOINER
-        state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
-        forwardDelete(state, 0);
-        state.assertEquals("| U+1F469");
-        forwardDelete(state, 0);
-        state.assertEquals("|");
+        // TODO(nona): Revive this test once HarfBuzz is updated to 2.0.2 (b/117953171)
+        // state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
+        // forwardDelete(state, 0);
+        // state.assertEquals("|");
 
         // Regional indicator symbol + emoji modifier
         state.setByString("| U+1F1FA U+1F3FB");
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index e891fc9..8646c68 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -307,6 +307,24 @@
     }
 
     @Test
+    public void testDetectLanguage() {
+        if (isTextClassifierDisabled()) return;
+        String text = "This is English text";
+        TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
+        TextLanguage textLanguage = mClassifier.detectLanguage(request);
+        assertThat(textLanguage, isTextLanguage("en"));
+    }
+
+    @Test
+    public void testDetectLanguage_japanese() {
+        if (isTextClassifierDisabled()) return;
+        String text = "これは日本語のテキストです";
+        TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
+        TextLanguage textLanguage = mClassifier.detectLanguage(request);
+        assertThat(textLanguage, isTextLanguage("ja"));
+    }
+
+    @Test
     public void testSetTextClassifier() {
         TextClassifier classifier = mock(TextClassifier.class);
         mTcm.setTextClassifier(classifier);
@@ -444,4 +462,23 @@
             }
         };
     }
+
+    private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
+        return new BaseMatcher<TextLanguage>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof TextLanguage) {
+                    TextLanguage result = (TextLanguage) o;
+                    return result.getLocaleHypothesisCount() > 0
+                            && languageTag.equals(result.getLocale(0).toLanguageTag());
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("locale=").appendValue(languageTag);
+            }
+        };
+    }
 }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 44f8737..28e92db 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -146,6 +146,7 @@
         <permission name="android.permission.CLEAR_APP_CACHE"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
+        <permission name="android.permission.GET_APP_OPS_STATS"/>
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
     </privapp-permissions>
 
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index ea0a109..3db240b 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -83,7 +83,7 @@
 
     // ---------------------------------------------------------------------------
     // Drawing methods
-    // These are also implemented in DisplayListCanvas so that we can
+    // These are also implemented in RecordingCanvas so that we can
     // selectively apply on them
     // Everything below here is copy/pasted from Canvas.java
     // The JNI registration is handled by android_view_Canvas.cpp
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 1cd756f..632edfa 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -31,8 +31,6 @@
 import android.os.Trace;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 import android.view.ThreadedRenderer;
 
 import dalvik.annotation.optimization.CriticalNative;
@@ -1296,8 +1294,8 @@
             final RenderNode node = RenderNode.create("BitmapTemporary", null);
             node.setLeftTopRightBottom(0, 0, width, height);
             node.setClipToBounds(false);
-            node.setAllowForceDark(false);
-            final DisplayListCanvas canvas = node.start(width, height);
+            node.setForceDarkAllowed(false);
+            final RecordingCanvas canvas = node.start(width, height);
             if (source.getWidth() != width || source.getHeight() != height) {
                 canvas.scale(width / (float) source.getWidth(),
                         height / (float) source.getHeight());
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index f7acb11..f6d801b 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -17,6 +17,7 @@
 package android.graphics;
 
 import android.annotation.UnsupportedAppUsage;
+
 import java.io.InputStream;
 import java.io.OutputStream;
 
@@ -216,7 +217,7 @@
         public PictureCanvas(Picture pict, long nativeCanvas) {
             super(nativeCanvas);
             mPicture = pict;
-            // Disable bitmap density scaling. This matches DisplayListCanvas.
+            // Disable bitmap density scaling. This matches RecordingCanvas.
             mDensity = 0;
         }
 
diff --git a/core/java/android/view/DisplayListCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
similarity index 86%
rename from core/java/android/view/DisplayListCanvas.java
rename to graphics/java/android/graphics/RecordingCanvas.java
index 667fab5..7af006b 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -14,47 +14,47 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.graphics;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
-import android.graphics.BaseRecordingCanvas;
-import android.graphics.Bitmap;
-import android.graphics.CanvasProperty;
-import android.graphics.Paint;
 import android.util.Pools.SynchronizedPool;
+import android.view.TextureLayer;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 /**
  * A Canvas implementation that records view system drawing operations for deferred rendering.
- * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
+ * This is intended for use with RenderNode. This class keeps a list of all the Paint and
  * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
- * the DisplayList is still holding a native reference to the memory.
+ * the RecordingCanvas is still holding a native reference to the memory.
  *
  * @hide
  */
-public final class DisplayListCanvas extends BaseRecordingCanvas {
+public final class RecordingCanvas extends BaseRecordingCanvas {
     // The recording canvas pool should be large enough to handle a deeply nested
     // view hierarchy because display lists are generated recursively.
     private static final int POOL_LIMIT = 25;
 
     public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
 
-    private static final SynchronizedPool<DisplayListCanvas> sPool =
+    private static final SynchronizedPool<RecordingCanvas> sPool =
             new SynchronizedPool<>(POOL_LIMIT);
 
-    RenderNode mNode;
+    /**
+     * TODO: Temporarily exposed for RenderNodeAnimator(Set)
+     * @hide */
+    public RenderNode mNode;
     private int mWidth;
     private int mHeight;
 
-    static DisplayListCanvas obtain(@NonNull RenderNode node, int width, int height) {
+    static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
         if (node == null) throw new IllegalArgumentException("node cannot be null");
-        DisplayListCanvas canvas = sPool.acquire();
+        RecordingCanvas canvas = sPool.acquire();
         if (canvas == null) {
-            canvas = new DisplayListCanvas(node, width, height);
+            canvas = new RecordingCanvas(node, width, height);
         } else {
             nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode,
                     width, height);
@@ -83,7 +83,7 @@
     // Constructors
     ///////////////////////////////////////////////////////////////////////////
 
-    private DisplayListCanvas(@NonNull RenderNode node, int width, int height) {
+    private RecordingCanvas(@NonNull RenderNode node, int width, int height) {
         super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
         mDensity = 0; // disable bitmap density scaling
     }
@@ -95,7 +95,7 @@
 
     @Override
     public void setDensity(int density) {
-        // drop silently, since DisplayListCanvas doesn't perform density scaling
+        // drop silently, since RecordingCanvas doesn't perform density scaling
     }
 
     @Override
@@ -156,6 +156,8 @@
      * functionality used by webview for calling into their renderer from our display lists.
      *
      * @param drawGLFunction A native function pointer
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public void callDrawGLFunction2(long drawGLFunction) {
@@ -166,13 +168,15 @@
      * Records the functor specified with the drawGLFunction function pointer. This is
      * functionality used by webview for calling into their renderer from our display lists.
      *
-     * @param drawGLFunction A native function pointer
+     * @param drawGLFunctor A native function pointer
      * @param releasedCallback Called when the display list is destroyed, and thus
      * the functor is no longer referenced by this canvas's display list.
      *
      * NOTE: The callback does *not* necessarily mean that there are no longer
      * any references to the functor, just that the reference from this specific
      * canvas's display list has been released.
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) {
@@ -201,8 +205,9 @@
      * Draws the specified layer onto this canvas.
      *
      * @param layer The layer to composite on this canvas
+     * @hide
      */
-    void drawTextureLayer(TextureLayer layer) {
+    public void drawTextureLayer(TextureLayer layer) {
         nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle());
     }
 
@@ -210,6 +215,16 @@
     // Drawing
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     * Draws a circle
+     *
+     * @param cx
+     * @param cy
+     * @param radius
+     * @param paint
+     *
+     * @hide
+     */
     @UnsupportedAppUsage
     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
             CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
@@ -217,6 +232,19 @@
                 radius.getNativeContainer(), paint.getNativeContainer());
     }
 
+    /**
+     * Draws a round rect
+     *
+     * @param left
+     * @param top
+     * @param right
+     * @param bottom
+     * @param rx
+     * @param ry
+     * @param paint
+     *
+     * @hide
+     */
     public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
             CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
             CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
diff --git a/core/java/android/view/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
similarity index 92%
rename from core/java/android/view/RenderNode.java
rename to graphics/java/android/graphics/RenderNode.java
index 8ae9127..b61488c 100644
--- a/core/java/android/view/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.graphics;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
-import android.graphics.Matrix;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Rect;
+import android.view.NativeVectorDrawableAnimator;
+import android.view.RenderNodeAnimator;
+import android.view.View;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -36,7 +35,7 @@
 /**
  * <p>A display list records a series of graphics related operations and can replay
  * them later. Display lists are usually built by recording operations on a
- * {@link DisplayListCanvas}. Replaying the operations from a display list avoids
+ * {@link RecordingCanvas}. Replaying the operations from a display list avoids
  * executing application code on every frame, and is thus much more efficient.</p>
  *
  * <p>Display lists are used internally for all views by default, and are not
@@ -53,7 +52,7 @@
  * affected paragraph needs to be recorded again.</p>
  *
  * <h3>Hardware acceleration</h3>
- * <p>Display lists can only be replayed using a {@link DisplayListCanvas}. They are not
+ * <p>Display lists can only be replayed using a {@link RecordingCanvas}. They are not
  * supported in software. Always make sure that the {@link android.graphics.Canvas}
  * you are using to render a display list is hardware accelerated using
  * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
@@ -63,7 +62,7 @@
  *     ThreadedRenderer renderer = myView.getThreadedRenderer();
  *     if (renderer != null) {
  *         DisplayList displayList = renderer.createDisplayList();
- *         DisplayListCanvas canvas = displayList.start(width, height);
+ *         RecordingCanvas canvas = displayList.start(width, height);
  *         try {
  *             // Draw onto the canvas
  *             // For instance: canvas.drawBitmap(...);
@@ -77,7 +76,7 @@
  * <pre class="prettyprint">
  *     protected void onDraw(Canvas canvas) {
  *         if (canvas.isHardwareAccelerated()) {
- *             DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ *             RecordingCanvas displayListCanvas = (RecordingCanvas) canvas;
  *             displayListCanvas.drawDisplayList(mDisplayList);
  *         }
  *     }
@@ -102,7 +101,7 @@
  * <pre class="prettyprint">
  *     private void createDisplayList() {
  *         mDisplayList = DisplayList.create("MyDisplayList");
- *         DisplayListCanvas canvas = mDisplayList.start(width, height);
+ *         RecordingCanvas canvas = mDisplayList.start(width, height);
  *         try {
  *             for (Bitmap b : mBitmaps) {
  *                 canvas.drawBitmap(b, 0.0f, 0.0f, null);
@@ -115,7 +114,7 @@
  *
  *     protected void onDraw(Canvas canvas) {
  *         if (canvas.isHardwareAccelerated()) {
- *             DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ *             RecordingCanvas displayListCanvas = (RecordingCanvas) canvas;
  *             displayListCanvas.drawDisplayList(mDisplayList);
  *         }
  *     }
@@ -143,10 +142,10 @@
                 RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
     }
 
-    /** Not for general use; use only if you are ThreadedRenderer or DisplayListCanvas.
+    /** Not for general use; use only if you are ThreadedRenderer or RecordingCanvas.
      * @hide
      */
-    final long mNativeRenderNode;
+    public final long mNativeRenderNode;
     private final AnimationHost mAnimationHost;
 
     private RenderNode(String name, AnimationHost animationHost) {
@@ -195,7 +194,7 @@
      *
      * @hide
      */
-    interface PositionUpdateListener {
+    public interface PositionUpdateListener {
 
         /**
          * Called by native by a Rendering Worker thread to update window position
@@ -228,7 +227,7 @@
      * stored in this display list.
      *
      * Calling this method will mark the render node invalid until
-     * {@link #end(DisplayListCanvas)} is called.
+     * {@link #end(RecordingCanvas)} is called.
      * Only valid render nodes can be replayed.
      *
      * @param width The width of the recording viewport
@@ -236,19 +235,19 @@
      *
      * @return A canvas to record drawing operations.
      *
-     * @see #end(DisplayListCanvas)
+     * @see #end(RecordingCanvas)
      * @see #isValid()
      */
     @UnsupportedAppUsage
-    public DisplayListCanvas start(int width, int height) {
-        return DisplayListCanvas.obtain(this, width, height);
+    public RecordingCanvas start(int width, int height) {
+        return RecordingCanvas.obtain(this, width, height);
     }
 
     /**
      * Same as {@link #start(int, int)} but with the RenderNode's width & height
      */
-    public DisplayListCanvas start() {
-        return DisplayListCanvas.obtain(this,
+    public RecordingCanvas start() {
+        return RecordingCanvas.obtain(this,
                 nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
     }
 
@@ -261,7 +260,7 @@
      * @see #isValid()
      */
     @UnsupportedAppUsage
-    public void end(DisplayListCanvas canvas) {
+    public void end(RecordingCanvas canvas) {
         long displayList = canvas.finishRecording();
         nSetDisplayList(mNativeRenderNode, displayList);
         canvas.recycle();
@@ -292,14 +291,32 @@
     // Matrix manipulation
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     * Whether or not the RenderNode has an identity transform. This is a faster
+     * way to do the otherwise equivalent {@link #getMatrix(Matrix)} {@link Matrix#isIdentity()}
+     * as it doesn't require copying the Matrix first, thus minimizing overhead.
+     *
+     * @return true if the RenderNode has an identity transform, false otherwise
+     */
     public boolean hasIdentityMatrix() {
         return nHasIdentityMatrix(mNativeRenderNode);
     }
 
+    /**
+     * Gets the current transform matrix
+     *
+     * @param outMatrix The matrix to store the transform of the RenderNode
+     */
     public void getMatrix(@NonNull Matrix outMatrix) {
         nGetTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
     }
 
+    /**
+     * Gets the current transform inverted. This is a faster way to do the otherwise
+     * equivalent {@link #getMatrix(Matrix)} followed by {@link Matrix#invert(Matrix)}
+     *
+     * @param outMatrix The matrix to store the inverse transform of the RenderNode
+     */
     public void getInverseMatrix(@NonNull Matrix outMatrix) {
         nGetInverseTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
     }
@@ -308,14 +325,25 @@
     // RenderProperty Setters
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     * TODO
+     */
     public boolean setLayerType(int layerType) {
         return nSetLayerType(mNativeRenderNode, layerType);
     }
 
+    /**
+     * TODO
+     */
     public boolean setLayerPaint(@Nullable Paint paint) {
         return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
     }
 
+    /**
+     * Sets the clip bounds of the RenderNode.
+     * @param rect the bounds to clip to. If null, the clip bounds are reset
+     * @return True if the clip bounds changed, false otherwise
+     */
     public boolean setClipBounds(@Nullable Rect rect) {
         if (rect == null) {
             return nSetClipBoundsEmpty(mNativeRenderNode);
@@ -371,8 +399,10 @@
             case Outline.MODE_EMPTY:
                 return nSetOutlineEmpty(mNativeRenderNode);
             case Outline.MODE_ROUND_RECT:
-                return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
-                        outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
+                return nSetOutlineRoundRect(mNativeRenderNode,
+                        outline.mRect.left, outline.mRect.top,
+                        outline.mRect.right, outline.mRect.bottom,
+                        outline.mRadius, outline.mAlpha);
             case Outline.MODE_CONVEX_PATH:
                 return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
                         outline.mAlpha);
@@ -381,6 +411,9 @@
         throw new IllegalArgumentException("Unrecognized outline?");
     }
 
+    /**
+     * @return True if this RenderNode has a shadow, false otherwise
+     */
     public boolean hasShadow() {
         return nHasShadow(mNativeRenderNode);
     }
@@ -414,6 +447,11 @@
         return nSetClipToOutline(mNativeRenderNode, clipToOutline);
     }
 
+    /**
+     * See {@link #setClipToOutline(boolean)}
+     *
+     * @return True if this RenderNode clips to its outline, false otherwise
+     */
     public boolean getClipToOutline() {
         return nGetClipToOutline(mNativeRenderNode);
     }
@@ -518,10 +556,21 @@
         return nHasOverlappingRendering(mNativeRenderNode);
     }
 
+    /**
+     * Sets the base elevation of this RenderNode in pixels
+     *
+     * @param lift the elevation in pixels
+     * @return true if the elevation changed, false if it was the same
+     */
     public boolean setElevation(float lift) {
         return nSetElevation(mNativeRenderNode, lift);
     }
 
+    /**
+     * See {@link #setElevation(float)}
+     *
+     * @return The RenderNode's current elevation
+     */
     public float getElevation() {
         return nGetElevation(mNativeRenderNode);
     }
@@ -882,16 +931,16 @@
      * @param allow Whether or not to allow force dark.
      * @return true If the value has changed, false otherwise.
      */
-    public boolean setAllowForceDark(boolean allow) {
+    public boolean setForceDarkAllowed(boolean allow) {
         return nSetAllowForceDark(mNativeRenderNode, allow);
     }
 
     /**
-     * See {@link #setAllowForceDark(boolean)}
+     * See {@link #setForceDarkAllowed(boolean)}
      *
      * @return true if force dark is allowed (default), false if it is disabled
      */
-    public boolean getAllowForceDark() {
+    public boolean isForceDarkAllowed() {
         return nGetAllowForceDark(mNativeRenderNode);
     }
 
@@ -906,9 +955,12 @@
      * bit of a kludge.
      *
      * @hide */
-    interface AnimationHost {
+    public interface AnimationHost {
+        /** checkstyle */
         void registerAnimatingRenderNode(RenderNode animator);
+        /** checkstyle */
         void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator);
+        /** checkstyle */
         boolean isAttached();
     }
 
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 6c1372f..789e38c 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -39,7 +39,9 @@
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.os.Build;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
@@ -50,9 +52,7 @@
 import android.util.Property;
 import android.util.TimeUtils;
 import android.view.Choreographer;
-import android.view.DisplayListCanvas;
 import android.view.NativeVectorDrawableAnimator;
-import android.view.RenderNode;
 import android.view.RenderNodeAnimatorSetHelper;
 import android.view.View;
 
@@ -1542,11 +1542,11 @@
         }
 
         /**
-         * Holds a weak reference to the target that was last seen (through the DisplayListCanvas
+         * Holds a weak reference to the target that was last seen (through the RecordingCanvas
          * in the last draw call), so that when animator set needs to start, we can add the animator
          * to the last seen RenderNode target and start right away.
          */
-        protected void recordLastSeenTarget(DisplayListCanvas canvas) {
+        protected void recordLastSeenTarget(RecordingCanvas canvas) {
             final RenderNode node = RenderNodeAnimatorSetHelper.getTarget(canvas);
             mLastSeenTarget = new WeakReference<RenderNode>(node);
             // Add the animator to the list of animators on every draw
@@ -1742,7 +1742,7 @@
         @Override
         public void onDraw(Canvas canvas) {
             if (canvas.isHardwareAccelerated()) {
-                recordLastSeenTarget((DisplayListCanvas) canvas);
+                recordLastSeenTarget((RecordingCanvas) canvas);
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
index 626bcee..c1f8798 100644
--- a/graphics/java/android/graphics/drawable/RippleComponent.java
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -16,15 +16,8 @@
 
 package android.graphics.drawable;
 
-import android.animation.Animator;
-import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
-import android.view.DisplayListCanvas;
-import android.view.RenderNodeAnimator;
-
-import java.util.ArrayList;
 
 /**
  * Abstract class that handles size & positioning common to the ripple & focus states.
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index a8dc34a..cce9ba3 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -23,10 +23,10 @@
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.util.FloatProperty;
 import android.util.MathUtils;
-import android.view.DisplayListCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
@@ -132,7 +132,7 @@
         }
     }
 
-    private void startPending(DisplayListCanvas c) {
+    private void startPending(RecordingCanvas c) {
         if (!mPendingHwAnimators.isEmpty()) {
             for (int i = 0; i < mPendingHwAnimators.size(); i++) {
                 RenderNodeAnimator animator = mPendingHwAnimators.get(i);
@@ -164,7 +164,7 @@
         }
     }
 
-    private void drawHardware(DisplayListCanvas c, Paint p) {
+    private void drawHardware(RecordingCanvas c, Paint p) {
         startPending(c);
         pruneHwFinished();
         if (mPropPaint != null) {
@@ -332,11 +332,11 @@
      * @param p the paint used to draw the ripple
      */
     public void draw(Canvas c, Paint p) {
-        final boolean hasDisplayListCanvas = !mForceSoftware && c instanceof DisplayListCanvas;
+        final boolean hasDisplayListCanvas = !mForceSoftware && c instanceof RecordingCanvas;
 
         pruneSwFinished();
         if (hasDisplayListCanvas) {
-            final DisplayListCanvas hw = (DisplayListCanvas) c;
+            final RecordingCanvas hw = (RecordingCanvas) c;
             drawHardware(hw, p);
         } else {
             drawSoftware(c, p);
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 3ca0f81..13d2dae 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -71,15 +71,12 @@
         paint.setAlpha(layer->getAlpha());
         paint.setBlendMode(layer->getMode());
         paint.setColorFilter(layer->getColorSpaceWithFilter());
-        if (layer->getForceFilter()) {
-            paint.setFilterQuality(kLow_SkFilterQuality);
-        }
-
         const bool nonIdentityMatrix = !matrix.isIdentity();
         if (nonIdentityMatrix) {
             canvas->save();
             canvas->concat(matrix);
         }
+        const SkMatrix& totalMatrix = canvas->getTotalMatrix();
         if (dstRect || srcRect) {
             SkMatrix matrixInv;
             if (!matrix.invert(&matrixInv)) {
@@ -99,9 +96,28 @@
                 skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight);
             }
             matrixInv.mapRect(&skiaDestRect);
+            // If (matrix is identity or an integer translation) and (src/dst buffers size match),
+            // then use nearest neighbor, otherwise use bilerp sampling.
+            // Integer translation is defined as when src rect and dst rect align fractionally.
+            // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works
+            // only for SrcOver blending and without color filter (readback uses Src blending).
+            bool isIntegerTranslate = totalMatrix.isTranslate()
+                    && SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX])
+                    == SkScalarFraction(skiaSrcRect.fLeft)
+                    && SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY])
+                    == SkScalarFraction(skiaSrcRect.fTop);
+            if (layer->getForceFilter() || !isIntegerTranslate) {
+                paint.setFilterQuality(kLow_SkFilterQuality);
+            }
             canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint,
                                   SkCanvas::kFast_SrcRectConstraint);
         } else {
+            bool isIntegerTranslate = totalMatrix.isTranslate()
+                    && SkScalarIsInt(totalMatrix[SkMatrix::kMTransX])
+                    && SkScalarIsInt(totalMatrix[SkMatrix::kMTransY]);
+            if (layer->getForceFilter() || !isIntegerTranslate) {
+                paint.setFilterQuality(kLow_SkFilterQuality);
+            }
             canvas->drawImage(layerImage.get(), 0, 0, &paint);
         }
         // restore the original matrix
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 38204a5..a02b6af 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -1068,6 +1068,7 @@
         ENCODING_E_AC3_JOC,
         ENCODING_DTS,
         ENCODING_DTS_HD,
+        ENCODING_MP3,
         ENCODING_IEC61937,
         ENCODING_AAC_HE_V1,
         ENCODING_AAC_HE_V2,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e8c97bc..274da11 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1379,14 +1379,20 @@
     //====================================================================
     // Offload query
     /**
-     * @hide
      * Returns whether offloaded playback of an audio format is supported on the device.
-     * Offloaded playback is where the decoding of an audio stream is not competing with other
-     * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
+     * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
+     * is not competing with other software resources. In general, it is supported by dedicated
+     * hardware, such as audio DSPs.
+     * <p>Note that this query only provides information about the support of an audio format,
+     * it does not indicate whether the resources necessary for the offloaded playback are
+     * available at that instant.
      * @param format the audio format (codec, sample rate, channels) being checked.
      * @return true if the given audio format can be offloaded.
      */
-    public boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+        if (format == null) {
+            throw new IllegalArgumentException("Illegal null AudioFormat");
+        }
         return AudioSystem.isOffloadSupported(format);
     }
 
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e8fe9fe..67cc456 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.audiopolicy.AudioMix;
+import android.os.Build;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -864,9 +865,9 @@
     public static native int setMasterMono(boolean mono);
 
     // helpers for android.media.AudioManager.getProperty(), see description there for meaning
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552)
     public static native int getPrimaryOutputSamplingRate();
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552)
     public static native int getPrimaryOutputFrameCount();
     @UnsupportedAppUsage
     public static native int getOutputLatency(int stream);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 62e58ca..3ec595d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -23,7 +23,7 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.NioUtils;
-import java.util.Collection;
+import java.util.LinkedList;
 import java.util.concurrent.Executor;
 
 import android.annotation.CallbackExecutor;
@@ -31,16 +31,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
-import android.app.ActivityThread;
-import android.content.Context;
+import android.os.Build;
+import android.os.Binder;
 import android.os.Handler;
-import android.os.IBinder;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -191,9 +188,8 @@
     private static final int NATIVE_EVENT_NEW_POS = 4;
     /**
      * Callback for more data
-     * TODO only for offload
      */
-    private static final int NATIVE_EVENT_MORE_DATA = 0;
+    private static final int NATIVE_EVENT_CAN_WRITE_MORE_DATA = 9;
     /**
      * IAudioTrack tear down for offloaded tracks
      * TODO: when received, java AudioTrack must be released
@@ -202,7 +198,6 @@
     /**
      * Event id denotes when all the buffers queued in AF and HW are played
      * back (after stop is called) for an offloaded track.
-     * TODO: not just for offload
      */
     private static final int NATIVE_EVENT_STREAM_END = 7;
 
@@ -392,6 +387,10 @@
      * Offset of the first sample of the audio in byte from start of HW_AV_SYNC track AV header.
      */
     private int mOffset = 0;
+    /**
+     * Indicates whether the track is intended to play in offload mode.
+     */
+    private boolean mOffloaded = false;
 
     //--------------------------------
     // Used exclusively by native code
@@ -614,6 +613,7 @@
             encoding = format.getEncoding();
         }
         audioParamCheck(rate, channelMask, channelIndexMask, encoding, mode);
+        mOffloaded = offload;
         mStreamType = AudioSystem.STREAM_DEFAULT;
 
         audioBuffSizeCheck(bufferSizeInBytes);
@@ -901,7 +901,6 @@
         }
 
         /**
-         * @hide
          * Sets whether this track will play through the offloaded audio path.
          * When set to true, at build time, the audio format will be checked against
          * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
@@ -960,8 +959,11 @@
                         .build();
             }
 
-            //TODO tie offload to PERFORMANCE_MODE_POWER_SAVING?    
             if (mOffload) {
+                if (mPerformanceMode == PERFORMANCE_MODE_LOW_LATENCY) {
+                    throw new UnsupportedOperationException(
+                            "Offload and low latency modes are incompatible");
+                }
                 if (mAttributes.getUsage() != AudioAttributes.USAGE_MEDIA) {
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload requires USAGE_MEDIA");
@@ -1223,6 +1225,9 @@
      * Releases the native AudioTrack resources.
      */
     public void release() {
+        synchronized (mStreamEventCbLock){
+            endStreamEventHandling();
+        }
         // even though native_release() stops the native AudioTrack, we need to stop
         // AudioTrack subclasses too.
         try {
@@ -1506,7 +1511,7 @@
      * a better solution.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552)
     public int getLatency() {
         return native_get_latency();
     }
@@ -2282,7 +2287,8 @@
             return ERROR_BAD_VALUE;
         }
 
-        int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,
+
+        final int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,
                 writeMode == WRITE_BLOCKING);
 
         if ((mDataLoadMode == MODE_STATIC)
@@ -2391,7 +2397,7 @@
             return ERROR_BAD_VALUE;
         }
 
-        int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat,
+        final int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat,
                 writeMode == WRITE_BLOCKING);
 
         if ((mDataLoadMode == MODE_STATIC)
@@ -2479,7 +2485,7 @@
             return ERROR_BAD_VALUE;
         }
 
-        int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat,
+        final int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat,
                 writeMode == WRITE_BLOCKING);
 
         if ((mDataLoadMode == MODE_STATIC)
@@ -2986,68 +2992,205 @@
     }
 
     /**
-     * @hide
-     * Abstract class to receive event notification about the stream playback.
-     * See {@link AudioTrack#setStreamEventCallback(Executor, StreamEventCallback)} to register
+     * Abstract class to receive event notifications about the stream playback in offloaded mode.
+     * See {@link AudioTrack#registerStreamEventCallback(Executor, StreamEventCallback)} to register
      * the callback on the given {@link AudioTrack} instance.
      */
     public abstract static class StreamEventCallback {
-        /** @hide */ // add hidden empty constructor so it doesn't show in SDK
-        public StreamEventCallback() { }
         /**
          * Called when an offloaded track is no longer valid and has been discarded by the system.
          * An example of this happening is when an offloaded track has been paused too long, and
          * gets invalidated by the system to prevent any other offload.
-         * @param track the {@link AudioTrack} on which the event happened
+         * @param track the {@link AudioTrack} on which the event happened.
          */
         public void onTearDown(AudioTrack track) { }
         /**
          * Called when all the buffers of an offloaded track that were queued in the audio system
          * (e.g. the combination of the Android audio framework and the device's audio hardware)
          * have been played after {@link AudioTrack#stop()} has been called.
-         * @param track the {@link AudioTrack} on which the event happened
+         * @param track the {@link AudioTrack} on which the event happened.
          */
-        public void onStreamPresentationEnd(AudioTrack track) { }
+        public void onPresentationEnded(AudioTrack track) { }
         /**
          * Called when more audio data can be written without blocking on an offloaded track.
-         * @param track the {@link AudioTrack} on which the event happened
+         * @param track the {@link AudioTrack} on which the event happened.
+         * @param sizeInFrames the number of frames available to write without blocking.
+         *   Note that the frame size of a compressed stream is 1 byte.
          */
-        public void onStreamDataRequest(AudioTrack track) { }
+        public void onDataRequest(AudioTrack track, int sizeInFrames) { }
     }
 
-    private Executor mStreamEventExec;
-    private StreamEventCallback mStreamEventCb;
-    private final Object mStreamEventCbLock = new Object();
-
     /**
-     * @hide
-     * Sets the callback for the notification of stream events.
-     * @param executor {@link Executor} to handle the callbacks
-     * @param eventCallback the callback to receive the stream event notifications
+     * Registers a callback for the notification of stream events.
+     * This callback can only be registered for instances operating in offloaded mode
+     * (see {@link AudioTrack.Builder#setOffloadedPlayback(boolean)} and
+     * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} for more details).
+     * @param executor {@link Executor} to handle the callbacks.
+     * @param eventCallback the callback to receive the stream event notifications.
      */
-    public void setStreamEventCallback(@NonNull @CallbackExecutor Executor executor,
+    public void registerStreamEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull StreamEventCallback eventCallback) {
         if (eventCallback == null) {
             throw new IllegalArgumentException("Illegal null StreamEventCallback");
         }
+        if (!mOffloaded) {
+            throw new IllegalStateException(
+                    "Cannot register StreamEventCallback on non-offloaded AudioTrack");
+        }
         if (executor == null) {
             throw new IllegalArgumentException("Illegal null Executor for the StreamEventCallback");
         }
         synchronized (mStreamEventCbLock) {
-            mStreamEventExec = executor;
-            mStreamEventCb = eventCallback;
+            // check if eventCallback already in list
+            for (StreamEventCbInfo seci : mStreamEventCbInfoList) {
+                if (seci.mStreamEventCb == eventCallback) {
+                    throw new IllegalArgumentException(
+                            "StreamEventCallback already registered");
+                }
+            }
+            beginStreamEventHandling();
+            mStreamEventCbInfoList.add(new StreamEventCbInfo(executor, eventCallback));
         }
     }
 
     /**
-     * @hide
-     * Unregisters the callback for notification of stream events, previously set
-     * by {@link #setStreamEventCallback(Executor, StreamEventCallback)}.
+     * Unregisters the callback for notification of stream events, previously registered
+     * with {@link #registerStreamEventCallback(Executor, StreamEventCallback)}.
+     * @param eventCallback the callback to unregister.
      */
-    public void removeStreamEventCallback() {
+    public void unregisterStreamEventCallback(@NonNull StreamEventCallback eventCallback) {
+        if (eventCallback == null) {
+            throw new IllegalArgumentException("Illegal null StreamEventCallback");
+        }
+        if (!mOffloaded) {
+            throw new IllegalStateException("No StreamEventCallback on non-offloaded AudioTrack");
+        }
         synchronized (mStreamEventCbLock) {
-            mStreamEventExec = null;
-            mStreamEventCb = null;
+            StreamEventCbInfo seciToRemove = null;
+            for (StreamEventCbInfo seci : mStreamEventCbInfoList) {
+                if (seci.mStreamEventCb == eventCallback) {
+                    // ok to remove while iterating over list as we exit iteration
+                    mStreamEventCbInfoList.remove(seci);
+                    if (mStreamEventCbInfoList.size() == 0) {
+                        endStreamEventHandling();
+                    }
+                    return;
+                }
+            }
+            throw new IllegalArgumentException("StreamEventCallback was not registered");
+        }
+    }
+
+    //---------------------------------------------------------
+    // Offload
+    //--------------------
+    private static class StreamEventCbInfo {
+        final Executor mStreamEventExec;
+        final StreamEventCallback mStreamEventCb;
+
+        StreamEventCbInfo(Executor e, StreamEventCallback cb) {
+            mStreamEventExec = e;
+            mStreamEventCb = cb;
+        }
+    }
+
+    private final Object mStreamEventCbLock = new Object();
+    @GuardedBy("mStreamEventCbLock")
+    @NonNull private LinkedList<StreamEventCbInfo> mStreamEventCbInfoList =
+            new LinkedList<StreamEventCbInfo>();
+    /**
+     * Dedicated thread for handling the StreamEvent callbacks
+     */
+    private @Nullable HandlerThread mStreamEventHandlerThread;
+    private @Nullable volatile StreamEventHandler mStreamEventHandler;
+
+    /**
+     * Called from native AudioTrack callback thread, filter messages if necessary
+     * and repost event on AudioTrack message loop to prevent blocking native thread.
+     * @param what event code received from native
+     * @param arg optional argument for event
+     */
+    void handleStreamEventFromNative(int what, int arg) {
+        if (mStreamEventHandler == null) {
+            return;
+        }
+        switch (what) {
+            case NATIVE_EVENT_CAN_WRITE_MORE_DATA:
+                // replace previous CAN_WRITE_MORE_DATA messages with the latest value
+                mStreamEventHandler.removeMessages(NATIVE_EVENT_CAN_WRITE_MORE_DATA);
+                mStreamEventHandler.sendMessage(
+                        mStreamEventHandler.obtainMessage(
+                                NATIVE_EVENT_CAN_WRITE_MORE_DATA, arg, 0/*ignored*/));
+                break;
+            case NATIVE_EVENT_NEW_IAUDIOTRACK:
+                mStreamEventHandler.sendMessage(
+                        mStreamEventHandler.obtainMessage(NATIVE_EVENT_NEW_IAUDIOTRACK));
+                break;
+            case NATIVE_EVENT_STREAM_END:
+                mStreamEventHandler.sendMessage(
+                        mStreamEventHandler.obtainMessage(NATIVE_EVENT_STREAM_END));
+                break;
+        }
+    }
+
+    private class StreamEventHandler extends Handler {
+
+        StreamEventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final LinkedList<StreamEventCbInfo> cbInfoList;
+            synchronized (mStreamEventCbLock) {
+                if (mStreamEventCbInfoList.size() == 0) {
+                    return;
+                }
+                cbInfoList = new LinkedList<StreamEventCbInfo>(mStreamEventCbInfoList);
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                for (StreamEventCbInfo cbi : cbInfoList) {
+                    switch (msg.what) {
+                        case NATIVE_EVENT_CAN_WRITE_MORE_DATA:
+                            cbi.mStreamEventExec.execute(() ->
+                                    cbi.mStreamEventCb.onDataRequest(AudioTrack.this, msg.arg1));
+                            break;
+                        case NATIVE_EVENT_NEW_IAUDIOTRACK:
+                            // TODO also release track as it's not longer usable
+                            cbi.mStreamEventExec.execute(() ->
+                                    cbi.mStreamEventCb.onTearDown(AudioTrack.this));
+                            break;
+                        case NATIVE_EVENT_STREAM_END:
+                            cbi.mStreamEventExec.execute(() ->
+                                    cbi.mStreamEventCb.onPresentationEnded(AudioTrack.this));
+                            break;
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @GuardedBy("mStreamEventCbLock")
+    private void beginStreamEventHandling() {
+        if (mStreamEventHandlerThread == null) {
+            mStreamEventHandlerThread = new HandlerThread(TAG + ".StreamEvent");
+            mStreamEventHandlerThread.start();
+            final Looper looper = mStreamEventHandlerThread.getLooper();
+            if (looper != null) {
+                mStreamEventHandler = new StreamEventHandler(looper);
+            }
+        }
+    }
+
+    @GuardedBy("mStreamEventCbLock")
+    private void endStreamEventHandling() {
+        if (mStreamEventHandlerThread != null) {
+            mStreamEventHandlerThread.quit();
+            mStreamEventHandlerThread = null;
         }
     }
 
@@ -3135,7 +3278,7 @@
     private static void postEventFromNative(Object audiotrack_ref,
             int what, int arg1, int arg2, Object obj) {
         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
-        final AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
+        final AudioTrack track = (AudioTrack) ((WeakReference) audiotrack_ref).get();
         if (track == null) {
             return;
         }
@@ -3145,29 +3288,11 @@
             return;
         }
 
-        if (what == NATIVE_EVENT_MORE_DATA || what == NATIVE_EVENT_NEW_IAUDIOTRACK
+        if (what == NATIVE_EVENT_CAN_WRITE_MORE_DATA
+                || what == NATIVE_EVENT_NEW_IAUDIOTRACK
                 || what == NATIVE_EVENT_STREAM_END) {
-            final Executor exec;
-            final StreamEventCallback cb;
-            synchronized (track.mStreamEventCbLock) {
-                exec = track.mStreamEventExec;
-                cb = track.mStreamEventCb;
-            }
-            if ((exec == null) || (cb == null)) {
-                return;
-            }
-            switch (what) {
-                case NATIVE_EVENT_MORE_DATA:
-                    exec.execute(() -> cb.onStreamDataRequest(track));
-                    return;
-                case NATIVE_EVENT_NEW_IAUDIOTRACK:
-                    // TODO also release track as it's not longer usable
-                    exec.execute(() -> cb.onTearDown(track));
-                    return;
-                case NATIVE_EVENT_STREAM_END:
-                    exec.execute(() -> cb.onStreamPresentationEnd(track));
-                    return;
-            }
+            track.handleStreamEventFromNative(what, arg1);
+            return;
         }
 
         NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate;
@@ -3180,7 +3305,6 @@
         }
     }
 
-
     //---------------------------------------------------------
     // Native methods called from the Java side
     //--------------------
diff --git a/media/java/android/media/Media2HTTPService.java b/media/java/android/media/Media2HTTPService.java
index 957acec..0d46ce4 100644
--- a/media/java/android/media/Media2HTTPService.java
+++ b/media/java/android/media/Media2HTTPService.java
@@ -18,9 +18,6 @@
 
 import android.util.Log;
 
-import java.net.CookieHandler;
-import java.net.CookieManager;
-import java.net.CookieStore;
 import java.net.HttpCookie;
 import java.util.List;
 
@@ -38,45 +35,8 @@
     public Media2HTTPConnection makeHTTPConnection() {
 
         synchronized (mCookieStoreInitialized) {
-            // Only need to do it once for all connections
-            if ( !mCookieStoreInitialized )  {
-                CookieHandler cookieHandler = CookieHandler.getDefault();
-                if (cookieHandler == null) {
-                    cookieHandler = new CookieManager();
-                    CookieHandler.setDefault(cookieHandler);
-                    Log.v(TAG, "makeHTTPConnection: CookieManager created: " + cookieHandler);
-                } else {
-                    Log.v(TAG, "makeHTTPConnection: CookieHandler (" + cookieHandler + ") exists.");
-                }
-
-                // Applying the bootstrapping cookies
-                if ( mCookies != null ) {
-                    if ( cookieHandler instanceof CookieManager ) {
-                        CookieManager cookieManager = (CookieManager)cookieHandler;
-                        CookieStore store = cookieManager.getCookieStore();
-                        for ( HttpCookie cookie : mCookies ) {
-                            try {
-                                store.add(null, cookie);
-                            } catch ( Exception e ) {
-                                Log.v(TAG, "makeHTTPConnection: CookieStore.add" + e);
-                            }
-                            //for extended debugging when needed
-                            //Log.v(TAG, "MediaHTTPConnection adding Cookie[" + cookie.getName() +
-                            //        "]: " + cookie);
-                        }
-                    } else {
-                        Log.w(TAG, "makeHTTPConnection: The installed CookieHandler is not a "
-                                + "CookieManager. Can’t add the provided cookies to the cookie "
-                                + "store.");
-                    }
-                }   // mCookies
-
-                mCookieStoreInitialized = true;
-
-                Log.v(TAG, "makeHTTPConnection(" + this + "): cookieHandler: " + cookieHandler +
-                        " Cookies: " + mCookies);
-            }   // mCookieStoreInitialized
-        }   // synchronized
+            Media2Utils.storeCookies(mCookies);
+        }
 
         return new Media2HTTPConnection();
     }
diff --git a/media/java/android/media/Media2Utils.java b/media/java/android/media/Media2Utils.java
new file mode 100644
index 0000000..066233d
--- /dev/null
+++ b/media/java/android/media/Media2Utils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.util.Log;
+
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.CookieStore;
+import java.net.HttpCookie;
+import java.util.List;
+
+/** @hide */
+public class Media2Utils {
+    private static final String TAG = "Media2Utils";
+
+    private Media2Utils() {
+    }
+
+    public static synchronized void storeCookies(List<HttpCookie> cookies) {
+        CookieHandler cookieHandler = CookieHandler.getDefault();
+        if (cookieHandler == null) {
+            cookieHandler = new CookieManager();
+            CookieHandler.setDefault(cookieHandler);
+            Log.v(TAG, "storeCookies: CookieManager created: " + cookieHandler);
+        } else {
+            Log.v(TAG, "storeCookies: CookieHandler (" + cookieHandler + ") exists.");
+        }
+
+        if (cookies != null) {
+            if (cookieHandler instanceof CookieManager) {
+                CookieManager cookieManager = (CookieManager)cookieHandler;
+                CookieStore store = cookieManager.getCookieStore();
+                for (HttpCookie cookie : cookies) {
+                    try {
+                        store.add(null, cookie);
+                    } catch (Exception e) {
+                        Log.v(TAG, "storeCookies: CookieStore.add" + cookie, e);
+                    }
+                }
+            } else {
+                Log.w(TAG, "storeCookies: The installed CookieHandler is not a CookieManager."
+                        + " Can’t add the provided cookies to the cookie store.");
+            }
+        }   // cookies
+
+        Log.v(TAG, "storeCookies: cookieHandler: " + cookieHandler + " Cookies: " + cookies);
+
+    }
+
+}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 71df7dc..6263e5d 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -834,10 +834,11 @@
             path = uri.getPath();
         } else if (scheme != null) {
             // handle non-file sources
+            Media2Utils.storeCookies(cookies);
             nativeHandleDataSourceUrl(
                 isCurrent,
                 srcId,
-                Media2HTTPService.createHTTPService(path, cookies),
+                Media2HTTPService.createHTTPService(path),
                 path,
                 keys,
                 values,
@@ -3276,12 +3277,12 @@
         }
 
         @Override
-        public void onStreamPresentationEnd(AudioTrack track) {
+        public void onPresentationEnded(AudioTrack track) {
             native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
         }
 
         @Override
-        public void onStreamDataRequest(AudioTrack track) {
+        public void onDataRequest(AudioTrack track, int size) {
             native_stream_event_onStreamDataRequest(
                     mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
         }
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 9eb0c6d..cf7bf19 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -365,4 +365,22 @@
             return Integer.MAX_VALUE;
         }
     }
+
+    /**
+     * Synchronously get state of the indicated model.  The model state is returned as
+     * a recognition event, or null if the model is not loaded, or if this method
+     * is not supported.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+    public SoundTrigger.RecognitionEvent getModelState(UUID soundModelId) {
+        if (soundModelId == null) {
+            return null;
+        }
+        try {
+            return mSoundTriggerService.getModelState(new ParcelUuid(soundModelId));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/opengl/java/android/opengl/EGL15.java b/opengl/java/android/opengl/EGL15.java
index 9aae6ad..f855fe2 100644
--- a/opengl/java/android/opengl/EGL15.java
+++ b/opengl/java/android/opengl/EGL15.java
@@ -146,4 +146,22 @@
         int flags
     );
 
+    // C function EGLImage eglCreateImage ( EGLDisplay dpy, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list )
+
+    public static native EGLImage eglCreateImage(
+        EGLDisplay dpy,
+        EGLContext context,
+        int target,
+        long buffer,
+        long[] attrib_list,
+        int offset
+    );
+
+    // C function EGLBoolean eglDestroyImage ( EGLDisplay dpy, EGLImage image )
+
+    public static native boolean eglDestroyImage(
+        EGLDisplay dpy,
+        EGLImage image
+    );
+
 }
diff --git a/packages/ExternalStorageProvider/Android.bp b/packages/ExternalStorageProvider/Android.bp
new file mode 100644
index 0000000..973fef3
--- /dev/null
+++ b/packages/ExternalStorageProvider/Android.bp
@@ -0,0 +1,19 @@
+android_app {
+    name: "ExternalStorageProvider",
+
+    manifest: "AndroidManifest.xml",
+
+    resource_dirs: [
+        "res",
+    ],
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    platform_apis: true,
+
+    certificate: "platform",
+
+    privileged: true,
+}
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
deleted file mode 100644
index 9e99313..0000000
--- a/packages/ExternalStorageProvider/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := ExternalStorageProvider
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-include $(BUILD_PACKAGE)
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
index 1072f95..484dbcc 100644
--- a/packages/ExternalStorageProvider/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -17,6 +17,10 @@
             <intent-filter>
                 <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
             </intent-filter>
+            <!-- Stub that allows MediaProvider to make incoming calls -->
+            <path-permission
+                android:path="/media_internal"
+                android:permission="android.permission.WRITE_MEDIA_STORAGE" />
         </provider>
 
         <receiver android:name=".MountReceiver">
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 62207c5..4e52ff6d 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -37,6 +37,7 @@
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Path;
 import android.provider.DocumentsContract.Root;
+import android.provider.MediaStore;
 import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -606,11 +607,16 @@
                     }
                     break;
                 }
-                case "getDocumentId": {
-                    final String path = arg;
-                    final List<UriPermission> accessUriPermissions =
-                            extras.getParcelableArrayList(AUTHORITY + ".extra.uriPermissions");
+                case MediaStore.GET_DOCUMENT_URI_CALL: {
+                    // All callers must go through MediaProvider
+                    getContext().enforceCallingPermission(
+                            android.Manifest.permission.WRITE_MEDIA_STORAGE, TAG);
 
+                    final Uri fileUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+                    final List<UriPermission> accessUriPermissions = extras
+                            .getParcelableArrayList(DocumentsContract.EXTRA_URI_PERMISSIONS);
+
+                    final String path = fileUri.getPath();
                     try {
                         final Bundle out = new Bundle();
                         final Uri uri = getDocumentUri(path, accessUriPermissions);
@@ -619,7 +625,22 @@
                     } catch (FileNotFoundException e) {
                         throw new IllegalStateException("File in " + path + " is not found.", e);
                     }
+                }
+                case MediaStore.GET_MEDIA_URI_CALL: {
+                    // All callers must go through MediaProvider
+                    getContext().enforceCallingPermission(
+                            android.Manifest.permission.WRITE_MEDIA_STORAGE, TAG);
 
+                    final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+                    final String docId = DocumentsContract.getDocumentId(documentUri);
+                    try {
+                        final Bundle out = new Bundle();
+                        final Uri uri = Uri.fromFile(getFileForDocId(docId));
+                        out.putParcelable(DocumentsContract.EXTRA_URI, uri);
+                        return out;
+                    } catch (FileNotFoundException e) {
+                        throw new IllegalStateException(e);
+                    }
                 }
                 default:
                     Log.w(TAG, "unknown method passed to call(): " + method);
diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp
new file mode 100644
index 0000000..83427d4
--- /dev/null
+++ b/packages/ExternalStorageProvider/tests/Android.bp
@@ -0,0 +1,25 @@
+android_test {
+    name: "ExternalStorageProviderTests",
+
+    manifest: "AndroidManifest.xml",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    libs: [
+        "android.test.base",
+        "android.test.mock",
+        "android.test.runner",
+    ],
+
+    static_libs: [
+        "android-support-test",
+        "mockito-target",
+        "truth-prebuilt",
+    ],
+
+    certificate: "platform",
+
+    instrumentation_for: "ExternalStorageProvider",
+}
diff --git a/packages/ExternalStorageProvider/tests/AndroidManifest.xml b/packages/ExternalStorageProvider/tests/AndroidManifest.xml
new file mode 100644
index 0000000..58b6e86
--- /dev/null
+++ b/packages/ExternalStorageProvider/tests/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.externalstorage.tests">
+
+    <application android:label="ExternalStorageProvider Tests">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.externalstorage"
+                     android:label="ExternalStorageProvider Tests" />
+</manifest>
+
diff --git a/packages/ExternalStorageProvider/tests/AndroidTest.xml b/packages/ExternalStorageProvider/tests/AndroidTest.xml
new file mode 100644
index 0000000..e5fa73f
--- /dev/null
+++ b/packages/ExternalStorageProvider/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="Runs Tests for ExternalStorageProvider.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="ExternalStorageProviderTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="ExternalStorageProviderTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.externalstorage.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
new file mode 100644
index 0000000..a88b3e1
--- /dev/null
+++ b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.externalstorage;
+
+import static com.android.externalstorage.ExternalStorageProvider.AUTHORITY;
+
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.pm.ProviderInfo;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ExternalStorageProviderTest {
+    @Test
+    public void onCreate_shouldUpdateVolumes() throws Exception {
+        ExternalStorageProvider externalStorageProvider = new ExternalStorageProvider();
+        ExternalStorageProvider spyProvider = spy(externalStorageProvider);
+        ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.authority = AUTHORITY;
+        providerInfo.grantUriPermissions = true;
+        providerInfo.exported = true;
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                spyProvider.attachInfoForTesting(
+                        InstrumentationRegistry.getTargetContext(), providerInfo);
+            }
+        });
+
+        verify(spyProvider, atLeast(1)).updateVolumes();
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
index 78963f3..027ca09 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
@@ -102,8 +102,4 @@
     public void count(Context context, String name, int value) {
         MetricsLogger.count(context, name, value);
     }
-
-    public void histogram(Context context, String name, int bucket) {
-        MetricsLogger.histogram(context, name, bucket);
-    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
index 4b9f572..379a820 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
@@ -76,9 +76,4 @@
      * Logs a count.
      */
     void count(Context context, String name, int value);
-
-    /**
-     * Logs a histogram event.
-     */
-    void histogram(Context context, String name, int bucket);
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 1e5b378..662fa10 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -59,44 +59,18 @@
         }
     }
 
-    /**
-     * Logs a user action. Includes the elapsed time since the containing
-     * fragment has been visible.
-     */
-    public void action(VisibilityLoggerMixin visibilityLogger, int category, int value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(category, value,
-                    sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
-        }
-    }
-
-    /**
-     * Logs a user action. Includes the elapsed time since the containing
-     * fragment has been visible.
-     */
-    public void action(VisibilityLoggerMixin visibilityLogger, int category, boolean value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(category, value,
-                    sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
-        }
-    }
-
     public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
         for (LogWriter writer : mLoggerWriters) {
             writer.action(context, category, taggedData);
         }
     }
 
-    /** @deprecated use {@link #action(VisibilityLoggerMixin, int, int)} */
-    @Deprecated
     public void action(Context context, int category, int value) {
         for (LogWriter writer : mLoggerWriters) {
             writer.action(context, category, value);
         }
     }
 
-    /** @deprecated use {@link #action(VisibilityLoggerMixin, int, boolean)} */
-    @Deprecated
     public void action(Context context, int category, boolean value) {
         for (LogWriter writer : mLoggerWriters) {
             writer.action(context, category, value);
@@ -116,12 +90,6 @@
         }
     }
 
-    public void histogram(Context context, String name, int bucket) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.histogram(context, name, bucket);
-        }
-    }
-
     public int getMetricsCategory(Object object) {
         if (object == null || !(object instanceof Instrumentable)) {
             return MetricsEvent.VIEW_UNKNOWN;
@@ -153,7 +121,4 @@
                 Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
     }
 
-    private Pair<Integer, Object> sinceVisibleTaggedData(long timestamp) {
-        return Pair.create(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, timestamp);
-    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index f4fd779..7a7f0d4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -15,13 +15,10 @@
  */
 package com.android.settingslib.core.instrumentation;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -34,8 +31,6 @@
 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 org.robolectric.RuntimeEnvironment;
@@ -46,30 +41,20 @@
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
 public class MetricsFeatureProviderTest {
-    private static int CATEGORY = 10;
-    private static boolean SUBTYPE_BOOLEAN = true;
-    private static int SUBTYPE_INTEGER = 1;
-    private static long ELAPSED_TIME = 1000;
-
-    @Mock private LogWriter mockLogWriter;
-    @Mock private VisibilityLoggerMixin mockVisibilityLogger;
+    @Mock
+    private LogWriter mLogWriter;
 
     private Context mContext;
     private MetricsFeatureProvider mProvider;
 
-    @Captor
-    private ArgumentCaptor<Pair> mPairCaptor;
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
         mProvider = new MetricsFeatureProvider();
         List<LogWriter> writers = new ArrayList<>();
-        writers.add(mockLogWriter);
+        writers.add(mLogWriter);
         ReflectionHelpers.setField(mProvider, "mLoggerWriters", writers);
-
-        when(mockVisibilityLogger.elapsedTimeSinceVisible()).thenReturn(ELAPSED_TIME);
     }
 
     @Test
@@ -77,7 +62,7 @@
         mProvider.logDashboardStartIntent(mContext, null /* intent */,
                 MetricsEvent.SETTINGS_GESTURES);
 
-        verifyNoMoreInteractions(mockLogWriter);
+        verifyNoMoreInteractions(mLogWriter);
     }
 
     @Test
@@ -86,7 +71,7 @@
 
         mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
 
-        verify(mockLogWriter).action(
+        verify(mLogWriter).action(
                 eq(mContext),
                 eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
                 anyString(),
@@ -99,32 +84,10 @@
 
         mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
 
-        verify(mockLogWriter).action(
+        verify(mLogWriter).action(
                 eq(mContext),
                 eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
                 anyString(),
                 eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
     }
-
-    @Test
-    public void action_BooleanLogsElapsedTime() {
-        mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_BOOLEAN);
-        verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_BOOLEAN), mPairCaptor.capture());
-
-        Pair value = mPairCaptor.getValue();
-        assertThat(value.first instanceof Integer).isTrue();
-        assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
-        assertThat(value.second).isEqualTo(ELAPSED_TIME);
-    }
-
-    @Test
-    public void action_IntegerLogsElapsedTime() {
-        mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_INTEGER);
-        verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_INTEGER), mPairCaptor.capture());
-
-        Pair value = mPairCaptor.getValue();
-        assertThat(value.first instanceof Integer).isTrue();
-        assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
-        assertThat(value.second).isEqualTo(ELAPSED_TIME);
-    }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index b58ea00..f492208 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.plugins;
 
+import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Intent;
 
@@ -36,7 +37,17 @@
     void postStartActivityDismissingKeyguard(PendingIntent intent);
     void postQSRunnableDismissingKeyguard(Runnable runnable);
 
+    void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel,
+            boolean afterKeyguardGone);
+
     interface Callback {
         void onActivityStarted(int resultCode);
     }
+
+    interface OnDismissAction {
+        /**
+         * @return {@code true} if the dismiss should be deferred
+         */
+        boolean onDismiss();
+    }
 }
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
new file mode 100644
index 0000000..21c9051
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2018 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 android:height="36sp" android:viewportHeight="36"
+        android:viewportWidth="36" android:width="36sp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="?android:attr/colorAccent" android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"/>
+    <path android:fillColor="?android:attr/textColorPrimaryInverse" android:pathData="M17.59,13.41L21.17,17H7v2h14.17l-3.59,3.59L19,24l6,-6l-6,-6L17.59,13.41zM26,12v12h2V12H26z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml b/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml
new file mode 100644
index 0000000..51c442a
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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"
+        android:radius="40dp"/>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 41dd0b3..9c41fca 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -57,24 +57,6 @@
                     android:textColor="?attr/wallpaperTextColor"
                     android:contentDescription="@string/keyguard_accessibility_pin_area"
                     />
-            <ImageButton
-                    android:id="@+id/delete_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    android:gravity="center_vertical"
-                    android:src="@drawable/ic_backspace_black_24dp"
-                    android:clickable="true"
-                    android:paddingTop="8dip"
-                    android:paddingBottom="8dip"
-                    android:paddingRight="0dp"
-                    android:paddingLeft="0dp"
-                    android:background="@drawable/ripple_drawable"
-                    android:contentDescription="@string/keyboardview_keycode_delete"
-                    android:layout_alignEnd="@+id/pinEntry"
-                    android:layout_alignParentRight="true"
-                    android:tint="@color/pin_delete_color"
-                    android:tintMode="src_in"
-                    />
             <View
                     android:id="@+id/divider"
                     android:layout_width="match_parent"
@@ -186,10 +168,14 @@
                 android:layout_weight="1"
                 android:orientation="horizontal"
                 >
-            <Space
+            <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/delete_button"
                     android:layout_width="0px"
                     android:layout_height="match_parent"
                     android:layout_weight="1"
+                    android:background="@drawable/ripple_drawable_pin"
+                    android:contentDescription="@string/keyboardview_keycode_delete"
+                    style="@style/Keyguard.ImageButton.NumPadDelete"
                     />
             <com.android.keyguard.NumPadKey
                     android:id="@+id/key0"
@@ -204,10 +190,8 @@
                     android:layout_width="0px"
                     android:layout_height="match_parent"
                     android:layout_weight="1"
-                    android:paddingBottom="11sp"
-                    android:src="@drawable/ic_done_black_24dp"
                     style="@style/Keyguard.ImageButton.NumPadEnter"
-                    android:background="@drawable/ripple_drawable"
+                    android:background="@drawable/ripple_drawable_pin"
                     android:contentDescription="@string/keyboardview_keycode_enter"
                     />
         </LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
index a795442..7d8a1f5b 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
@@ -42,18 +42,11 @@
                          android:id="@+id/clock_view"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content" />
-                <View
-                    android:id="@+id/clock_separator"
-                    android:layout_width="@dimen/widget_separator_width"
-                    android:layout_height="@dimen/widget_separator_thickness"
-                    android:layout_below="@id/clock_view"
-                    android:background="#f00"
-                    android:layout_centerHorizontal="true" />
                 <include layout="@layout/keyguard_status_area"
                          android:id="@+id/keyguard_status_area"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
-                         android:layout_below="@id/clock_separator" />
+                         android:layout_below="@id/clock_view" />
             </RelativeLayout>
             <ImageView
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index 33f7e75..bfb5bf9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -71,24 +71,6 @@
                     android:textColor="?attr/wallpaperTextColor"
                     android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
                     />
-            <ImageButton
-                    android:id="@+id/delete_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    android:gravity="center_vertical"
-                    android:src="@drawable/ic_backspace_black_24dp"
-                    android:clickable="true"
-                    android:paddingTop="8dip"
-                    android:paddingBottom="8dip"
-                    android:paddingRight="0dp"
-                    android:paddingLeft="0dp"
-                    android:background="@drawable/ripple_drawable"
-                    android:contentDescription="@string/keyboardview_keycode_delete"
-                    android:layout_alignEnd="@+id/pinEntry"
-                    android:layout_alignParentRight="true"
-                    android:tint="@color/pin_delete_color"
-                    android:tintMode="src_in"
-                    />
             <View
                     android:id="@+id/divider"
                     android:layout_width="match_parent"
@@ -196,10 +178,14 @@
                 android:layout_weight="1"
                 android:orientation="horizontal"
                 >
-            <Space
+            <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/delete_button"
                     android:layout_width="0px"
                     android:layout_height="match_parent"
                     android:layout_weight="1"
+                    android:background="@drawable/ripple_drawable_pin"
+                    android:contentDescription="@string/keyboardview_keycode_delete"
+                    style="@style/Keyguard.ImageButton.NumPadDelete"
                     />
             <com.android.keyguard.NumPadKey
                     android:id="@+id/key0"
@@ -209,15 +195,13 @@
                     androidprv:textView="@+id/simPinEntry"
                     androidprv:digit="0"
                     />
-            <ImageButton
+            <com.android.keyguard.AlphaOptimizedImageButton
                     android:id="@+id/key_enter"
                     android:layout_width="0px"
                     android:layout_height="match_parent"
                     android:layout_weight="1"
-                    android:paddingBottom="11sp"
-                    android:src="@drawable/ic_done_black_24dp"
                     style="@style/Keyguard.ImageButton.NumPadEnter"
-                    android:background="@drawable/ripple_drawable"
+                    android:background="@drawable/ripple_drawable_pin"
                     android:contentDescription="@string/keyboardview_keycode_enter"
                     />
         </LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 4b385fc..9f3ae3a 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -72,24 +72,6 @@
                     android:textColor="?attr/wallpaperTextColor"
                     android:contentDescription="@string/keyguard_accessibility_sim_puk_area"
                     />
-            <ImageButton
-                    android:id="@+id/delete_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    android:gravity="center_vertical"
-                    android:src="@drawable/ic_backspace_black_24dp"
-                    android:clickable="true"
-                    android:paddingTop="8dip"
-                    android:paddingBottom="8dip"
-                    android:paddingRight="0dp"
-                    android:paddingLeft="0dp"
-                    android:background="@drawable/ripple_drawable"
-                    android:contentDescription="@string/keyboardview_keycode_delete"
-                    android:layout_alignEnd="@+id/pinEntry"
-                    android:layout_alignParentRight="true"
-                    android:tint="@color/pin_delete_color"
-                    android:tintMode="src_in"
-                    />
             <View
                     android:id="@+id/divider"
                     android:layout_width="match_parent"
@@ -197,10 +179,14 @@
                 android:layout_weight="1"
                 android:orientation="horizontal"
                 >
-            <Space
+            <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/delete_button"
                     android:layout_width="0px"
                     android:layout_height="match_parent"
                     android:layout_weight="1"
+                    android:background="@drawable/ripple_drawable_pin"
+                    android:contentDescription="@string/keyboardview_keycode_delete"
+                    style="@style/Keyguard.ImageButton.NumPadDelete"
                     />
             <com.android.keyguard.NumPadKey
                     android:id="@+id/key0"
@@ -210,15 +196,13 @@
                     androidprv:textView="@+id/pukEntry"
                     androidprv:digit="0"
                     />
-            <ImageButton
+            <com.android.keyguard.AlphaOptimizedImageButton
                     android:id="@+id/key_enter"
                     android:layout_width="0px"
                     android:layout_height="match_parent"
                     android:layout_weight="1"
-                    android:paddingBottom="11sp"
-                    android:src="@drawable/ic_done_black_24dp"
                     style="@style/Keyguard.ImageButton.NumPadEnter"
-                    android:background="@drawable/ripple_drawable"
+                    android:background="@drawable/ripple_drawable_pin"
                     android:contentDescription="@string/keyboardview_keycode_enter"
                     />
         </LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index dfa4bf9..00f8f86 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -43,6 +43,7 @@
               android:id="@+id/row"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
+              android:layout_marginTop="@dimen/subtitle_clock_padding"
               android:orientation="horizontal"
               android:gravity="center"
     />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 4ae2d41..32a7147 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -59,19 +59,11 @@
                  android:id="@+id/clock_view"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content" />
-            <View
-                android:id="@+id/clock_separator"
-                android:layout_width="@dimen/widget_separator_width"
-                android:layout_height="@dimen/widget_separator_thickness"
-                android:layout_below="@id/clock_view"
-                android:background="#f00"
-                android:layout_centerHorizontal="true" />
-
             <include layout="@layout/keyguard_status_area"
                 android:id="@+id/keyguard_status_area"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_below="@id/clock_separator" />
+                android:layout_below="@id/clock_view" />
         </RelativeLayout>
 
         <TextView
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 9984061..1106807 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -85,9 +85,9 @@
     <string name="kg_invalid_puk" msgid="5399287873762592502">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM karticu."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"PIN-ovi se ne poklapaju"</string>
     <string name="kg_login_too_many_attempts" msgid="6604574268387867255">"Previše puta ste pokušali otključati uređaj crtanjem uzorka"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"Pogrešno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"Pogrešno ste unijeli lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"Pogrešno ste nacrtali svoj uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"Pogrešno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"Pogrešno ste unijeli lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"Pogrešno ste nacrtali svoj uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1629351522209932316">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="3921998703529189931">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="4694232971224663735">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Tablet će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
@@ -100,8 +100,8 @@
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="2162434417489128282">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="8966727588974691544">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="8476407539834855">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="956706236554092172">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da tablet otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da telefon otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="956706236554092172">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da tablet otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da telefon otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"PIN za SIM karticu je netačan. Za otključavanje uređaja sada se morate obratiti svom operateru."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
       <item quantity="one">PIN za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index c2759da..d412252 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -37,7 +37,7 @@
     <string name="keyguard_plugged_in" msgid="3161102098900158923">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज होत आहे"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="3684592786276709342">"<xliff:g id="PERCENTAGE">%s</xliff:g> • वेगाने चार्ज होत आहे"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="509533586841478405">"<xliff:g id="PERCENTAGE">%s</xliff:g> • सावकाश चार्ज होत आहे"</string>
-    <string name="keyguard_low_battery" msgid="9218432555787624490">"आपला चार्जर कनेक्ट करा."</string>
+    <string name="keyguard_low_battery" msgid="9218432555787624490">"तुमचा चार्जर कनेक्ट करा."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"अनलॉक करण्यासाठी मेनू दाबा."</string>
     <string name="keyguard_network_locked_message" msgid="6743537524631420759">"नेटवर्क लॉक केले"</string>
     <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"सिम कार्ड नाही"</string>
@@ -84,9 +84,9 @@
     <string name="kg_invalid_puk" msgid="5399287873762592502">"योग्य PUK कोड पुन्हा एंटर करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"पिन कोड जुळत नाहीत"</string>
     <string name="kg_login_too_many_attempts" msgid="6604574268387867255">"खूप जास्त पॅटर्न प्रयत्न"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"तुम्ही आपला PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"तुम्ही आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"तुम्ही तुमचा PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"तुम्ही तुमचा पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1629351522209932316">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="3921998703529189931">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="4694232971224663735">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हे टॅबलेट रीसेट केले जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
@@ -99,8 +99,8 @@
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="2162434417489128282">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, ही कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="8966727588974691544">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="8476407539834855">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="956706236554092172">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून आपला फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="956706236554092172">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"सिम पिन कोड चुकीचा आहे तुम्ही आता तुमचे डिव्हाइस अनलॉक करण्‍यासाठी तुमच्या वाहकाशी संपर्क साधावा."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
       <item quantity="one">चुकीचा सिम पिन कोड, तुमच्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत.</item>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 787f91e..555f443 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -43,7 +43,7 @@
 
     <!-- Slice header -->
     <dimen name="widget_title_font_size">24dp</dimen>
-    <dimen name="widget_title_bottom_margin">7dp</dimen>
+    <dimen name="widget_title_bottom_margin">14dp</dimen>
     <dimen name="bottom_text_spacing_digital">0dp</dimen>
     <!-- Slice subtitle -->
     <dimen name="widget_label_font_size">16dp</dimen>
@@ -52,19 +52,17 @@
     <!-- Clock without header -->
     <dimen name="widget_big_font_size">64dp</dimen>
     <!-- Clock with header -->
+    <dimen name="widget_small_clock_padding">-25dp</dimen>
     <dimen name="widget_small_font_size">24dp</dimen>
     <dimen name="widget_small_font_stroke">0.6dp</dimen>
-    <!-- Dash between clock and header -->
-    <dimen name="widget_separator_width">12dp</dimen>
-    <dimen name="widget_separator_thickness">1dp</dimen>
-    <dimen name="widget_vertical_padding">26dp</dimen>
-    <dimen name="widget_icon_bottom_padding">14dp</dimen>
+    <dimen name="widget_vertical_padding">32dp</dimen>
     <!-- Subtitle paddings -->
     <dimen name="widget_horizontal_padding">8dp</dimen>
     <dimen name="widget_icon_size">16dp</dimen>
     <dimen name="widget_icon_padding">8dp</dimen>
-    <!-- Space between notification shelf and dash above it -->
-    <dimen name="widget_bottom_separator_padding">28dp</dimen>
+    <dimen name="subtitle_clock_padding">15dp</dimen>
+    <!-- Notification shelf padding when dark -->
+    <dimen name="widget_bottom_separator_padding">-6dp</dimen>
 
     <!-- The y translation to apply at the start in appear animations. -->
     <dimen name="appear_y_translation_start">32dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index b90b4dd..0462347 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -37,8 +37,16 @@
         <item name="android:textColor">?attr/wallpaperTextColor</item>
         <item name="android:paddingBottom">-16dp</item>
     </style>
+    <style name="Keyguard.ImageButton.NumPadDelete" parent="@android:style/Widget.ImageButton">
+        <item name="android:src">@drawable/ic_backspace_black_24dp</item>
+        <item name="android:paddingBottom">11sp</item>
+        <item name="android:tint">@color/pin_delete_color</item>
+        <item name="android:tintMode">src_in</item>
+        <item name="android:src">@drawable/ic_backspace_black_24dp</item>
+    </style>
     <style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.ImageButton">
-        <item name="android:tint">@color/background_protected</item>
+        <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
+        <item name="android:paddingBottom">11sp</item>
     </style>
     <style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
         <item name="android:textSize">12sp</item>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 3077433..395de19 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Diensverskaffernetwerk verander tans"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Maak batterybesonderhede oop"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Battery <xliff:g id="NUMBER">%d</xliff:g> persent."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Battery laai tans, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> persent."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Battery laai tans, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Stelselinstellings"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Kennisgewings"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Sien alle kennisgewings"</string>
@@ -319,6 +319,8 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Onbenoemde toestel"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gereed om uit te saai"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Geen toestelle beskikbaar nie"</string>
+    <!-- no translation found for quick_settings_cast_no_wifi (2696477881905521882) -->
+    <skip />
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Keer kleure om"</string>
@@ -782,6 +784,8 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Aangemeld as <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Geen internet nie"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Maak besonderhede oop."</string>
+    <!-- no translation found for accessibility_quick_settings_not_available (4190068184294019846) -->
+    <skip />
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Wysig volgorde van instellings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c0c0952..fcad97b 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"የአገልግሎት አቅራቢ አውታረ መረብን በመቀየር ላይ"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"የባትሪ ዝርዝሮችን ክፈት"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"የባትሪ <xliff:g id="NUMBER">%d</xliff:g> መቶኛ።"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ባትሪ ኃይል በመሙላት ላይ፣ <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> በመቶ።"</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ባትሪ ኃይል በመሙላት ላይ፣ <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"የስርዓት ቅንብሮች"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"ማሳወቂያዎች"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"ሁሉንም ማሳወቂያዎች ይመልከቱ"</string>
@@ -319,6 +319,8 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ያልተሰየመ መሳሪያ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ለመውሰድ ዝግጁ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"ምንም መሣሪያዎች አይገኙም"</string>
+    <!-- no translation found for quick_settings_cast_no_wifi (2696477881905521882) -->
+    <skip />
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ቀለማትን ግልብጥ"</string>
@@ -782,6 +784,8 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"እንደ <xliff:g id="ID_1">%s</xliff:g> ሆነው ገብተዋል"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ምንም በይነመረብ የለም"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"ዝርዝሮችን ክፈት።"</string>
+    <!-- no translation found for accessibility_quick_settings_not_available (4190068184294019846) -->
+    <skip />
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f7d5184..1b55d39 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -178,7 +178,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"فتح تفاصيل البطارية"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"مستوى البطارية <xliff:g id="NUMBER">%d</xliff:g> في المائة."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"جارٍ شحن البطارية، <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> بالمائة."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"جارٍ شحن البطارية، <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"إعدادات النظام."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"الإشعارات."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"الاطّلاع على جميع الإشعارات"</string>
@@ -327,6 +327,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"جهاز لا يحمل اسمًا"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"جاهز للإرسال"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"لا يتوفر أي جهاز"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"‏لم يتم الاتصال بشبكة Wi-Fi."</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"قلب الألوان"</string>
@@ -806,6 +807,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"تم تسجيل الدخول باعتبارك <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"لا يتوفر اتصال إنترنت."</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"فتح التفاصيل."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"غير متاحة بسبب <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"تعديل ترتيب الإعدادات."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -846,7 +848,7 @@
     <string name="notification_channel_battery" msgid="5786118169182888462">"البطارية"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"لقطات الشاشة"</string>
     <string name="notification_channel_general" msgid="4525309436693914482">"رسائل عامة"</string>
-    <string name="notification_channel_storage" msgid="3077205683020695313">"سعة التخزين"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"مساحة التخزين"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"تلميحات"</string>
     <string name="instant_apps" msgid="6647570248119804907">"التطبيقات الفورية"</string>
     <string name="instant_apps_title" msgid="8738419517367449783">"التطبيق <xliff:g id="APP">%1$s</xliff:g> قيد التشغيل"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 895faf8..65c5fb5 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"নাম নথকা ডিভাইচ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"কাষ্টৰ বাবে সাজু"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"কোনো ডিভাইচ নাই"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ৱাই-ফাইৰ সৈতে সংযোগ হৈ থকা নাই"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"উজ্জ্বলতা"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"স্বয়ং"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ৰং ওলোটা কৰক"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"আপোনাৰ স্ক্ৰীণত প্ৰদৰ্শন হোৱা সকলো <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> কেপশ্বাৰ কৰা আৰম্ভ কৰিব।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"পুনৰাই নেদেখুৱাব"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"সকলো মচক"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"পৰিচালনা"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"এতিয়াই আৰম্ভ কৰক"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"কোনো জাননী নাই"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> হিচাপে ছাইন ইন হ\'ল"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"বিৱৰণসমূহ খোলক।"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>ৰ বাবে উপলব্ধ নহয়"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>ৰ ছেটিংসমূহ খোলক।"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ছেটিংসমূহৰ ক্ৰম সম্পাদনা কৰক।"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>ৰ পৃষ্ঠা <xliff:g id="ID_1">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 461a328..07476aa 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Operator şəbəkəsinin dəyişilməsi"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Batareya detallarını açın"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batareya <xliff:g id="NUMBER">%d</xliff:g> faizdir."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batareya doldurulur, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> faiz."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batareya doldurulur, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%% faiz."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistem parametrləri"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Bildirişlər."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Bütün bildirişlərə baxın"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Adsız cihaz"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Yayıma hazırdır"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Heç bir cihaz əlçatan deyil"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi qoşulu deyil"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaqlıq"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AVTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Rəngləri çevirin"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> kimi daxil olunub"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"İnternet yoxdur"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Detalları açın."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> səbəbi ilə əlçatan deyil"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sıralanmasını redaktə edin."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ade59ab..db3834b 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -175,7 +175,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Promena mreže mobilnog operatera"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Otvori detalje o bateriji"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija je na <xliff:g id="NUMBER">%d</xliff:g> posto."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Baterija se puni, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procenata."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Baterija se puni, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistemska podešavanja."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obaveštenja."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Pogledajte sva obaveštenja"</string>
@@ -321,6 +321,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovani uređaj"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Spremno za prebacivanje"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nije dostupan nijedan uređaj"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi nije povezan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Osvetljenost"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKA"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Obrni boje"</string>
@@ -788,6 +789,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nema interneta"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otvori detalje."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nije dostupno iz sledećeg razloga: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index bea5c3f..7b19b36 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -178,7 +178,7 @@
     <!-- String.format failed for translation -->
     <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
     <skip />
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Зарадка акумулятара, працэнтаў: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Зарадка акумулятара: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Сістэмныя налады."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Апавяшчэнні."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Паказаць усе апавяшчэнні"</string>
@@ -325,6 +325,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Прылада без назвы"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Гатова для трансляцыі"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Няма даступных прылад"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi не падключаны"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркасць"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Інвертаваць колеры"</string>
@@ -796,6 +797,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Вы ўвайшлі як <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Не падключана да інтэрнэту"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Паказаць падрабязную інфармацыю."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Прычына недаступнасці: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c321593..74b1c44 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Промяна на мрежата на оператора"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Отваряне на подробностите за батерията"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> процента батерия."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батерията се зарежда – <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> процента."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батерията се зарежда – <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Системни настройки."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Известия."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Вижте всички известия"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Устройство без име"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово за предаване"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Няма налични устройства"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"не е установена връзка с Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Инвертиране на цветовете"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Влезли сте като <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Няма връзка с интернет"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Отвaряне на страницата с подробности."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Няма достъп, защото <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Редактиране на подредбата на настройките."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 138f2b0..5223a99 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"নামবিহীন ডিভাইস"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"কাস্ট করার জন্য প্রস্তুত"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"কোনো ডিভাইস উপলব্ধ নয়"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ওয়াই-ফাই কানেক্ট করা নেই"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"উজ্জ্বলতা"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"স্বয়ং"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"বিপরীত রঙ"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"সবকিছু সাফ করুন"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"পরিচালনা করুন"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"\'বিরক্ত করবেন না\' দিয়ে বিজ্ঞপ্তি পজ করা হয়েছে"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"এখন শুরু করুন"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"কোনো বিজ্ঞপ্তি নেই"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> হিসেবে প্রবেশ করে রয়েছেন"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ইন্টারনেট কানেকশন নেই"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"বিশদ বিবরণ খুলুন৷"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>-এর জন্য পাওয়া যাবে না"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 88115a5..ca09219 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -175,7 +175,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Promjena mreže mobilnog operatera"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Otvori detalje o potrošnji baterije"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija na <xliff:g id="NUMBER">%d</xliff:g> posto."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Punjenje baterije, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procenata."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Punjenje baterije, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Postavke sistema."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obavještenja."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Vidite sva obavještenja"</string>
@@ -321,6 +321,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovani uređaj"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Spreman za emitiranje"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nema dostupnih uređaja"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi mreža nije povezana"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Osvjetljenje"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverzija boja"</string>
@@ -790,6 +791,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nema internetske veze"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otvori detalje."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nije dostupno jer <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 27f043a..7b4fdad 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -63,7 +63,7 @@
     <string name="always_use_device" msgid="4015357883336738417">"Obre sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quan es connecti <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
     <string name="always_use_accessory" msgid="3257892669444535154">"Obre sempre <xliff:g id="APPLICATION">%1$s</xliff:g> quan es connecti <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Vols permetre la depuració per USB?"</string>
-    <string name="usb_debugging_message" msgid="2220143855912376496">"L\'empremta digital de la clau de RSA de l\'equip és:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"L\'empremta digital de la clau RSA de l\'equip és:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Dona sempre permís des d\'aquest equip"</string>
     <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"No es permet la depuració per USB"</string>
     <string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"L\'usuari que té iniciada la sessió al dispositiu en aquest moment no pot activar la depuració per USB. Per utilitzar aquesta funció, cal canviar a l\'usuari principal."</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositiu sense nom"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"A punt per emetre"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No hi ha cap dispositiu disponible."</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"La Wi‑Fi no està connectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverteix els colors"</string>
@@ -659,7 +660,7 @@
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Esquerra"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dreta"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
-    <string name="keyboard_key_tab" msgid="3871485650463164476">"Pestanya"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulador"</string>
     <string name="keyboard_key_space" msgid="2499861316311153293">"Espai"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"Retorn"</string>
     <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retrocés"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"S\'ha iniciat la sessió com a <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Sense connexió a Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Obre la informació detallada."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"No està disponible pel motiu següent: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edita l\'ordre de la configuració."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 7825ade..f8f79ce 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -176,9 +176,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Probíhá změna sítě operátora"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Otevřít podrobnosti o baterii"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Stav baterie: <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Baterie se nabíjí. Nabito: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systémová nastavení."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Oznámení."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Zobrazit všechna oznámení"</string>
@@ -325,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nepojmenované zařízení"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Připraveno k vysílání"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nejsou dostupná žádná zařízení"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Není připojena Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Převrátit barvy"</string>
@@ -796,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Jste přihlášeni jako <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nejste připojeni k internetu"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otevřít podrobnosti."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nedostupné, protože <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upravit pořadí nastavení."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 7ddcb5a..7894361 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Skift af mobilnetværk"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Åbn oplysninger om batteri"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batteri <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batteriet oplades. <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procent."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batteriet oplades. <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systemindstillinger."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Underretninger."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle underretninger"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Enhed uden navn"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Klar til at caste"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Der er ingen tilgængelige enheder"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Manglende Wi-Fi-forbindelse"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Byt om på farver"</string>
@@ -362,15 +363,15 @@
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er deaktiveret i sikker tilstand."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ryd alle"</string>
-    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Træk hertil for at bruge delt skærm"</string>
+    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Træk hertil for at bruge opdelt skærm"</string>
     <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Stryg opad for at skifte apps"</string>
     <string name="recents_quick_scrub_onboarding" msgid="2778062804333285789">"Træk til højre for hurtigt at skifte app"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
-    <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delt skærm øverst"</string>
-    <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delt skærm til venstre"</string>
-    <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delt skærm til højre"</string>
+    <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Opdelt skærm øverst"</string>
+    <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Opdelt skærm til venstre"</string>
+    <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Opdelt skærm til højre"</string>
     <string name="quick_step_accessibility_toggle_overview" msgid="7171470775439860480">"Slå Oversigt til/fra"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Oplader"</string>
@@ -752,7 +753,7 @@
     <item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
   </string-array>
     <string name="other" msgid="4060683095962566764">"Andet"</string>
-    <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til delt skærm"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til opdelt skærm"</string>
     <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Vis venstre del i fuld skærm"</string>
     <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"Venstre 70 %"</string>
     <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"Venstre 50 %"</string>
@@ -771,8 +772,8 @@
     <string name="accessibility_qs_edit_tile_move" msgid="3108103090006972938">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
     <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-underretning: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
-    <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i delt skærm."</string>
-    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke delt skærm."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i opdelt skærm."</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke opdelt skærm."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Appen fungerer muligvis ikke på sekundære skærme."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"Appen kan ikke åbnes på sekundære skærme."</string>
     <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Åbn Indstillinger."</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Logget ind som <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Intet internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Åbn oplysninger."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Ikke tilgængelig på grund af <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediger rækkefølgen af indstillinger."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index cd20971..47aaaed 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -323,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unbenanntes Gerät"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Startklar"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Keine Geräte verfügbar"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"WLAN nicht verbunden"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Farben umkehren"</string>
@@ -786,6 +787,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Angemeldet als <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Kein Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Details öffnen."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Aus diesem Grund nicht verfügbar: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Reihenfolge der Einstellungen bearbeiten."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -858,10 +860,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Zulassen"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Ablehnen"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Tippen zum Planen des Energiesparmodus"</string>
-    <string name="auto_saver_text" msgid="6324376061044218113">"Automatisch aktivieren bei einem Akkustand von <xliff:g id="PERCENTAGE">%d</xliff:g>%%"</string>
+    <string name="auto_saver_text" msgid="6324376061044218113">"Automatisch aktivieren bei einem Akkustand von <xliff:g id="PERCENTAGE">%d</xliff:g> %%"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Nein danke"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Geplanter Energiesparmodus aktiviert"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Der Energiesparmodus wird bei einem Akkustand von <xliff:g id="PERCENTAGE">%d</xliff:g>%% automatisch aktiviert."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Der Energiesparmodus wird bei einem Akkustand von <xliff:g id="PERCENTAGE">%d</xliff:g> %% automatisch aktiviert."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Einstellungen"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"OK"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0a35aec..ea16ba4 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Αλλαγή δικτύου εταιρείας κινητής τηλεφωνίας"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Άνοιγμα λεπτομερειών μπαταρίας"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Μπαταρία <xliff:g id="NUMBER">%d</xliff:g> τοις εκατό."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Φόρτιση μπαταρίας, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> τοις εκατό."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Φόρτιση μπαταρίας, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%% τοις εκατό."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Ρυθμίσεις συστήματος."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Ειδοποιήσεις."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Δείτε όλες τις ειδοποιήσεις"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Ανώνυμη συσκευή"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Έτοιμο για μετάδοση"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Δεν υπάρχουν διαθέσιμες συσκευές"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Το Wi-Fi δεν είναι συνδεδεμένο"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Αντιστροφή χρωμάτων"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Σύνδεση ως <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Άνοιγμα λεπτομερειών."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Μη διαθέσιμα λόγω <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 7fe3d9d..b7da383 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No devices available"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
@@ -443,7 +444,7 @@
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Manage"</string>
-    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do not disturb"</string>
+    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do Not Disturb"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"No Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Open details."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Unvailable due to <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 379e112..19e9b64 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No devices available"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
@@ -443,7 +444,7 @@
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Manage"</string>
-    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do not disturb"</string>
+    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do Not Disturb"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"No Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Open details."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Unvailable due to <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 7fe3d9d..b7da383 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No devices available"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
@@ -443,7 +444,7 @@
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Manage"</string>
-    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do not disturb"</string>
+    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do Not Disturb"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"No Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Open details."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Unvailable due to <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 7fe3d9d..b7da383 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No devices available"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
@@ -443,7 +444,7 @@
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Manage"</string>
-    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do not disturb"</string>
+    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifications paused by Do Not Disturb"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"No Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Open details."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Unvailable due to <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 5be13ea..97ddf61 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎Unnamed device‎‏‎‎‏‎"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎Ready to cast‎‏‎‎‏‎"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎No devices available‎‏‎‎‏‎"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎Wi‑Fi not connected‎‏‎‎‏‎"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎Brightness‎‏‎‎‏‎"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎AUTO‎‏‎‎‏‎"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎Invert colors‎‏‎‎‏‎"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎Signed in as ‎‏‎‎‏‏‎<xliff:g id="ID_1">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎No internet‎‏‎‎‏‎"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎Open details.‎‏‎‎‏‎"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‎Unvailable due to ‎‏‎‎‏‏‎<xliff:g id="REASON">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="ID_1">%s</xliff:g>‎‏‎‎‏‏‏‎ settings.‎‏‎‎‏‎"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‏‎Edit order of settings.‎‏‎‎‏‎"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎Page ‎‏‎‎‏‏‎<xliff:g id="ID_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎<xliff:g id="ID_2">%2$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 52b311b..35499f0 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Cambio de proveedor de red"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir detalles de la batería"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batería <xliff:g id="NUMBER">%d</xliff:g> por ciento"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Cargando batería: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Configuración del sistema"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificaciones"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Ver todas las notificaciones"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sin nombre"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Listo para transmitir"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No hay dispositivos disponibles"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"La red Wi-Fi no está conectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertir colores"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Accediste como <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Sin Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Abrir página de detalles"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"No disponible debido a <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar orden de configuración"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0329430..54364a5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Cambiando la red del operador"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir detalles de la batería"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> por ciento de batería"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batería cargando (<xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%)."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Ajustes del sistema"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificaciones"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Ver todas las notificaciones"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sin nombre"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Listo para enviar"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No hay dispositivos disponibles"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi sin conexión"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertir colores"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Has iniciado sesión como <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Sin Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Abrir detalles."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"No disponible (<xliff:g id="REASON">%s</xliff:g>)"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Cambiar el orden de los ajustes."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 80313e7..90e9334 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Operaatori võrku muudetakse"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Aku üksikasjade avamine"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Aku: <xliff:g id="NUMBER">%d</xliff:g> protsenti."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Akut laetakse (<xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%)."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Süsteemiseaded"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Märguanded"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Kõikide märguannete kuvamine"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nimeta seade"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Valmis ülekandmiseks"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Ühtegi seadet pole saadaval"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"WiFi-ühendus puudub"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Vaheta värve"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Sisse logitud kasutajana <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Interneti-ühendus puudub"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Ava üksikasjad."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Põhjuse <xliff:g id="REASON">%s</xliff:g> tõttu pole saadaval"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muuda seadete järjestust."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 9e19723..c6314e4 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Operadorearen sarea aldatzen"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Ireki bateriaren xehetasunak"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Bateriaren karga: <xliff:g id="NUMBER">%d</xliff:g>."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Kargatzen ari da bateria. %% <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> arte kargatu da oraingoz."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistemaren ezarpenak."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Jakinarazpenak."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Ikusi jakinarazpen guztiak"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Izenik gabeko gailua"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Igortzeko prest"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Ez dago gailurik erabilgarri"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Ez zaude konektatuta Wi-Fi sarera"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Distira"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIKOA"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Alderantzikatu koloreak"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> gisa hasi duzu saioa"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Ez dago Interneteko konexiorik"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Ireki xehetasunak."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Ez dago erabilgarri arrazoi honengatik: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editatu ezarpenen ordena."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7ef324f..ca38030 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"دستگاه بدون نام"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"آماده برای فرستادن"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"دستگاهی موجود نیست"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"‏Wi-Fi وصل نیست"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"برگردان رنگ‌ها"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"با <xliff:g id="ID_1">%s</xliff:g> به سیستم وارد شده‌اید"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"عدم اتصال به اینترنت"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"باز کردن جزئیات."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"به‌دلیل <xliff:g id="REASON">%s</xliff:g> دردسترس نیست"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ویرایش ترتیب تنظیمات."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dd82e08..412bee1 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nimetön laite"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Valmis lähetystä varten"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Laitteita ei ole käytettävissä"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fiä ei ole yhdistetty"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Käänteiset värit"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Kirjautunut tilillä <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Ei internetyhteyttä"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Avaa tiedot."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Ei käytettävissä, koska <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muokkaa asetusten järjestystä."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f9a9165..8821178 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Changer de réseau de fournisseur de services"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Ouvrir les détails de la pile"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Pile : <xliff:g id="NUMBER">%d</xliff:g> pour cent"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"La pile est en cours de charge : <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Paramètres système"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifications"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Afficher toutes les notifications"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Prêt à diffuser"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Aucun appareil à proximité"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Non connecté au Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverser les couleurs"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Connecté comme <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Aucune connexion Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Ouvrir les détails."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Non disponible pour la raison suivante : <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 297f8f4..e37722a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Modification du réseau de l\'opérateur"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Ouvrir les détails de la batterie"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batterie : <xliff:g id="NUMBER">%d</xliff:g> pour cent"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batterie en charge : <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Paramètres système"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifications"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Afficher toutes les notifications"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Prêt à caster"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Aucun appareil disponible."</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi non connecté"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverser les couleurs"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Connecté en tant que <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Aucun accès à Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Ouvrir les détails."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Indisponible pour la raison suivante : <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index bea5481..80f3c93 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Cambio de rede do operador"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir os detalles da batería"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Carga da batería: <xliff:g id="NUMBER">%d</xliff:g> por cento."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"A batería está cargando. Nivel: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Configuración do sistema"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificacións"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Ver todas as notificacións"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sen nome"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Listo para emitir"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Non hai dispositivos dispoñibles"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"A wifi non está conectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
@@ -403,9 +402,9 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string>
-    <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> para rematar a carga)"</string>
-    <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> para rematar a carga)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> para rematar a carga)"</string>
+    <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> para completar a carga)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> para completar a carga)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> para completar a carga)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar usuario, usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Iniciaches sesión como <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Non hai conexión a Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Abrir detalles."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Opcións non-dispoñibles polo seguinte motivo: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a orde das opcións de configuración."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index fd2c102..cf5692b 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"કૅરીઅર નેટવર્કમાં ફેરફાર થઈ રહ્યો છે"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"બૅટરીની વિગતો ખોલો"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"બૅટરી <xliff:g id="NUMBER">%d</xliff:g> ટકા."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"બૅટરી ચાર્જ થઈ રહી છે, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> ટકા."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"બૅટરી ચાર્જ થઈ રહી છે, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"સિસ્ટમ સેટિંગ્સ."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"નોટિફિકેશનો."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"બધી સૂચના જુઓ"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"અનામાંકિત ઉપકરણ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"કાસ્ટ કરવા માટે તૈયાર"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"કોઈ ઉપકરણો ઉપલબ્ધ નથી"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"વાઇ-ફાઇ કનેક્ટ નથી"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"તેજ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"સ્વતઃ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"રંગોને ઉલટાવો"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> તમારી સ્ક્રીન પર જે પ્રદર્શિત થાય છે તે દરેક વસ્તુને કેપ્ચર કરવાનું પ્રારંભ કરશે."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ફરીથી બતાવશો નહીં"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"બધુ સાફ કરો"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"મેનેજ કરો"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"ખલેલ પાડશો નહીં દ્વારા થોભાવેલ નોટિફિકેશન"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"હવે પ્રારંભ કરો"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"કોઈ સૂચનાઓ નથી"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> તરીકે સાઇન ઇન કર્યું"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"કોઈ ઇન્ટરનેટ નથી"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"વિગતો ખોલો."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>ને કારણે અનુપલબ્ધ છે"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
@@ -855,10 +856,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"મંજૂરી આપો"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"નકારો"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"બૅટરી સેવર શેડ્યૂલ કરવા માટે ટૅપ કરો"</string>
-    <string name="auto_saver_text" msgid="6324376061044218113">"બૅટરીનું સ્તર <xliff:g id="PERCENTAGE">%d</xliff:g>%% પર હોય ત્યારે આપમેળે ચાલુ કરો"</string>
+    <string name="auto_saver_text" msgid="6324376061044218113">"બૅટરીનું સ્તર <xliff:g id="PERCENTAGE">%d</xliff:g>%% પર હોય ત્યારે ઑટોમૅટિક રીતે ચાલુ કરો"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"ના, આભાર"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"બૅટરી સેવર શેડ્યૂલ ચાલુ થયું"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"બૅટરીનું સ્તર એકવાર <xliff:g id="PERCENTAGE">%d</xliff:g>%% કરતાં ઓછું થાય તે પછી બૅટરી સેવર આપમેળે ચાલુ થશે."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"બૅટરીનું સ્તર એકવાર <xliff:g id="PERCENTAGE">%d</xliff:g>%% કરતાં ઓછું થાય તે પછી બૅટરી સેવર ઑટોમૅટિક રીતે ચાલુ થશે."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"સેટિંગ"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"સમજાઈ ગયું"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index bf77c0d..ac34e9a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बदल रहा है"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"बैटरी का विवरण खोलें"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> प्रति‍शत बैटरी."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"बैटरी चार्ज हो रही है, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> प्रतिशत."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"बैटरी चार्ज हो रही है, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"सिस्टम सेटिंग."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"सूचनाएं."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"पूरी सूचनाएं देखें"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"अनाम डिवाइस"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"कास्ट करने के लिए तैयार"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"कोई डिवाइस उपलब्ध नहीं"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"वाई-फ़ाई कनेक्ट नहीं है"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"स्क्रीन की रोशनी"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"रंग उलटें"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> के रूप में प्रवेश किया हुआ है"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"इंटरनेट कनेक्शन नहीं है"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"विवरण खोलें."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> की वजह से मौजूद नहीं है"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग के क्रम को बदलें"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index cf54bef..5df6999 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -321,6 +321,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Uređaj bez naziva"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Spreman za emitiranje"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nema dostupnih uređaja"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi mreža nije povezana"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Zamjena boja"</string>
@@ -788,6 +789,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nema interneta"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otvaranje pojedinosti."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nije dostupno jer <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uređivanje redoslijeda postavki."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -850,7 +852,7 @@
     <string name="running_foreground_services_title" msgid="381024150898615683">"Izvođenje aplikacija u pozadini"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Dodirnite da biste vidjeli pojedinosti o potrošnji baterije i podatkovnom prometu"</string>
     <string name="mobile_data_disable_title" msgid="1068272097382942231">"Želite li isključiti mobilne podatke?"</string>
-    <string name="mobile_data_disable_message" msgid="4756541658791493506">"Nećete imati pristup mobilnim podacima ili internetu putem operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem Wi-Fi-ja."</string>
+    <string name="mobile_data_disable_message" msgid="4756541658791493506">"Nećete imati pristup mobilnim podacima ili internetu putem operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem Wi-Fija."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"vaš mobilni operater"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"Budući da aplikacija prekriva zahtjev za dopuštenje, Postavke ne mogu potvrditi vaš odgovor."</string>
     <string name="slice_permission_title" msgid="7465009437851044444">"Želite li dopustiti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 534cabd..f09a8b3 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Név nélküli eszköz"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Küldésre kész"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nem áll rendelkezésre eszköz"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Nem kapcsolódik Wi‑Fi-hálózathoz"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Színek invertálása"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Bejelentkezve mint <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nincs internetkapcsolat"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"A részletek megnyitása."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nem áll rendelkezésre a következő ok miatt: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Beállítások sorrendjének szerkesztése."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 3b4e773..8973ecf 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Անանուն սարք"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Պատրաստ է հեռարձակման"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Հասանելի սարքեր չկան"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi-ը միացված չէ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ավտոմատ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Շրջել գույները"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Մուտք է գործել որպես <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Ինտերնետ կապ չկա"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Բացել մանրամասները:"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Անհասանելի է, քանի որ <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Խմբագրել կարգավորումների հերթականությունը:"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ef5f2dc..2e3040c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Perangkat tanpa nama"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Siap melakukan transmisi"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Perangkat tak tersedia"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi tidak terhubung"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inversi warna"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Login sebagai <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Tidak ada internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Buka detail."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Tidak tersedia karena <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit urutan setelan."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 7119cb1..fd15fc3 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Skiptir um farsímakerfi"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Opna upplýsingar um rafhlöðu"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> prósent á rafhlöðu."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Rafhlaða í hleðslu, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> prósent."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Rafhlaða í hleðslu, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Kerfisstillingar."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Tilkynningar."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Sjá allar tilkynningar"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Ónefnt tæki"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Tilbúið í útsendingu"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Engin tæki til staðar"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi ekki tengt"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Birtustig"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SJÁLFVIRKT"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Umsnúa litum"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Skráð(ur) inn sem <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Engin nettenging"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Opna upplýsingasíðu."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Ekki tiltækt vegna <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Breyta röð stillinga."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 99f413d..37fabb8 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Cambio della rete dell\'operatore"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Visualizza i dettagli relativi alla batteria"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batteria: <xliff:g id="NUMBER">%d</xliff:g> percento."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batteria in carica, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Impostazioni di sistema."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifiche."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Visualizza tutte le notifiche"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo senza nome"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto a trasmettere"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nessun dispositivo disponibile"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Nessuna connessione Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverti colori"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Accesso eseguito come <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nessuna connessione a Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Apri i dettagli."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Non disponibile a causa di un problema <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifica l\'ordine delle impostazioni."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ad2003d..0d60e6c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -33,7 +33,7 @@
     </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"אין הודעות"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"מתמשך"</string>
-    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"הודעות"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
     <string name="battery_low_title" msgid="9187898087363540349">"ייתכן שהסוללה תתרוקן בקרוב"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"נותרו <xliff:g id="PERCENTAGE">%1$s</xliff:g>, נשארו בערך <xliff:g id="TIME">%2$s</xliff:g> על סמך השימוש במכשיר"</string>
@@ -51,7 +51,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"סיבוב אוטומטי של המסך"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"השתק"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"אוטומטי"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"הודעות"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"התראות"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"‏Bluetooth קשור"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"הגדר שיטות קלט"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"מקלדת פיזית"</string>
@@ -176,11 +176,11 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"רשת ספק משתנה"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"פתיחת פרטי סוללה"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> אחוזים של סוללה."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"טעינת סוללה, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> אחוז."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"טעינת סוללה, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"הגדרות מערכת"</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"הודעות"</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"התראות"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"הצגת כל ההודעות"</string>
-    <string name="accessibility_remove_notification" msgid="3603099514902182350">"נקה התראה"</string>
+    <string name="accessibility_remove_notification" msgid="3603099514902182350">"מחיקת התראה"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"‏GPS מופעל."</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"‏השגת GPS."</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"‏TeleTypewriter מופעל"</string>
@@ -195,7 +195,7 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"פתח מידע על האפליקציה <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
+    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"התראה נדחתה."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"לוח התראות."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"הגדרות מהירות."</string>
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"מסך נעילה."</string>
@@ -323,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"מכשיר ללא שם"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"מוכן להעביר"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"אין מכשירים זמינים"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"‏אין חיבור ל-Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"היפוך צבעים"</string>
@@ -342,7 +343,7 @@
       <item quantity="other">‏%d מכשירים</item>
       <item quantity="one">מכשיר אחד</item>
     </plurals>
-    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"הודעות"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"התראות"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"פנס"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"חבילת גלישה"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"שימוש בנתונים"</string>
@@ -542,7 +543,7 @@
     <string name="stream_ring" msgid="8213049469184048338">"צלצול"</string>
     <string name="stream_music" msgid="9086982948697544342">"מדיה"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"שעון מעורר"</string>
-    <string name="stream_notification" msgid="2563720670905665031">"הודעה"</string>
+    <string name="stream_notification" msgid="2563720670905665031">"התראה"</string>
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"‏טון זוגי מרובה תדרים (DTMF)"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"נגישות"</string>
@@ -614,8 +615,8 @@
     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"פקדים של הודעות הפעלה"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"פועל"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"כבוי"</string>
-    <string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של הודעות הפעלה, תוכל להגדיר רמת חשיבות מ-0 עד 5 להודעות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצג בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתר ממסך הנעילה ומשורת הסטטוס \n- הצג בתחתית רשימת ההודעות \n\n"<b>"רמה 0"</b>" \n- חסום את כל ההודעות מהאפליקציה"</string>
-    <string name="notification_header_default_channel" msgid="7506845022070889909">"הודעות"</string>
+    <string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של התראות הפעלה, אפשר להגדיר רמת חשיבות מ-0 עד 5 להתראות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצגה בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מניעת הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתרה ממסך הנעילה ומשורת הסטטוס \n- הצגה בתחתית רשימת ההתראות \n\n"<b>"רמה 0"</b>" \n- חסימה את כל ההתראות מהאפליקציה"</string>
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"התראות"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ההודעות האלה לא יוצגו לך יותר"</string>
     <string name="notification_channel_minimized" msgid="1664411570378910931">"ההודעות האלה ימוזערו"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"הודעות אלה בדרך כלל נדחות על ידיך. \nלהמשיך להציג אותן?"</string>
@@ -642,7 +643,7 @@
     <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
     <string name="inline_undo" msgid="558916737624706010">"ביטול"</string>
     <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="notification_menu_gear_description" msgid="2204480013726775108">"בקרת הודעות"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"בקרת התראות"</string>
     <string name="notification_menu_snooze_description" msgid="3653669438131034525">"אפשרויות של דחיית הודעות לטיפול בהמשך"</string>
     <string name="notification_menu_snooze_action" msgid="1112254519029621372">"הפעלת נודניק"</string>
     <string name="snooze_undo" msgid="6074877317002985129">"ביטול"</string>
@@ -693,7 +694,7 @@
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"דף הבית"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"מהזמן האחרון"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"הקודם"</string>
-    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"הודעות"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"התראות"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"מקשי קיצור במקלדת"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"החלפה של פריסת מקלדת"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"אפליקציות"</string>
@@ -782,7 +783,7 @@
     <string name="accessibility_qs_edit_tile_add" msgid="3520406665865985109">"הוספת <xliff:g id="TILE_NAME">%1$s</xliff:g> למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_move" msgid="3108103090006972938">"העברת <xliff:g id="TILE_NAME">%1$s</xliff:g> למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"עורך הגדרות מהירות."</string>
-    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"הודעת <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"התראות <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"ייתכן שהיישום לא יפעל עם מסך מפוצל."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"האפליקציה אינה תומכת במסך מפוצל."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
@@ -794,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"מחובר בתור <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"אין אינטרנט"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"פתיחת פרטים."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"לא זמין כי <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"עריכת סדר ההגדרות."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 81870e5..c651f9e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"携帯通信会社のネットワークを変更します"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"電池の詳細情報を開きます"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"電池残量: <xliff:g id="NUMBER">%d</xliff:g>パーセント"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"電池充電中: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"システム設定。"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"通知。"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"通知をすべて表示"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"名前のないデバイス"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"キャスト準備完了"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"利用可能なデバイスがありません"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi に接続されていません"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"色を反転"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> としてログインします"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"インターネットに接続されていません"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"詳細情報を開きます。"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"利用できない理由: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"設定の順序を編集します。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 7e71fbe..f91ffb0 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"ოპერატორის ქსელის შეცვლა"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"ბატარეის დეტალების გახსნა"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"ბატარეა: <xliff:g id="NUMBER">%d</xliff:g> პროცენტი."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ბატარეა იტენება, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> პროცენტი."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ბატარეა იტენება, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"სისტემის პარამეტრები."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"შეტყობინებები"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"ყველა შეტყობინების ნახვა"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"უსახელო მოწყობილობა"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"მზად არის სამაუწყებლოდ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"მოწყობილობები მიუწვდომელია"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi არ არის დაკავშირებული"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ფერების შებრუნება"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"შესული ხართ, როგორც <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ინტერნეტ-კავშირი არ არის"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"დეტალების გახსნა."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"მიუწვდომელია, რადგან <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"პარამეტრების მიმდევრობის რედაქტირება."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 89c7ff8..b79ea7b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Оператор желісін өзгерту"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Батарея мәліметтерін ашу"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Батарея <xliff:g id="NUMBER">%d</xliff:g> пайыз."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батарея зарядталуда, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> пайыз."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батарея зарядталуда, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Жүйе параметрлері."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Хабарлар."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Барлық хабарландыруды қарау"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Атаусыз құрылғы"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Трансляциялауға дайын"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Құрылғылар қол жетімді емес"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi желісіне жалғанбаған"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Жарықтығы"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Авто"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Түстерді инверсиялау"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ретінде кірдіңіз"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Интернетпен байланыс жоқ"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Мәліметтерді ашу."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Қолжетімді емес, өйткені <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Параметрлер тәртібін өзгерту."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 4d0c97c..0731a5e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ឧបករណ៍​​ដែល​មិន​មាន​ឈ្មោះ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ត្រៀម​រួចរាល់​ដើម្បី​ចាត់​ថ្នាក់"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"មិន​មាន​ឧបករណ៍​ដែល​អាច​ប្រើ​បាន"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"មិនមាន​ការតភ្ជាប់ Wi-Fi ទេ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ដាក់​​​បញ្ច្រាស​ពណ៌"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"បានចូលជា <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"គ្មាន​អ៊ីនធឺណិតទេ"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"បើកព័ត៌មានលម្អិត"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"មិនអាច​ប្រើបានទេ ដោយសារ <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"កែលំដាប់ការកំណត់"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 45f6944..c4c642f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"ವಾಹಕ ನೆಟ್‌ವರ್ಕ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"ಬ್ಯಾಟರಿ ವಿವರಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"ಬ್ಯಾಟರಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರತಿಶತ."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ಬ್ಯಾಟರಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> ಪ್ರತಿಶತ."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ಬ್ಯಾಟರಿ <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> ಪ್ರತಿಶತ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್‌ಗಳು."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"ಅಧಿಸೂಚನೆಗಳು."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನೋಡಿ"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ಹೆಸರಿಸದಿರುವ ಸಾಧನ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ಬಿತ್ತರಿಸಲು ಸಿದ್ದವಾಗಿದೆ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"ಯಾವುದೇ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ಪ್ರಕಾಶಮಾನ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ಸ್ವಯಂ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ಬಣ್ಣಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ಅವರಂತೆ ಸೈನ್ ಇನ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"ವಿವರಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> ಕಾರಣದಿಂದಾಗಿ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index dfa2bb4..9014880 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"이동통신사 네트워크 변경"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"배터리 세부정보 열기"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"배터리 <xliff:g id="NUMBER">%d</xliff:g>퍼센트"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"배터리 충전 중, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%입니다."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"시스템 설정"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"알림"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"모든 알림 보기"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"이름이 없는 기기"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"전송 준비 완료"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"사용 가능한 기기가 없습니다."</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi가 연결되어 있지 않음"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"색상 반전"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g>(으)로 로그인됨"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"인터넷 연결 없음"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"세부정보 열기"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"다음 이유로 사용할 수 없음: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"설정 순서 수정"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
@@ -856,14 +856,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"허용"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"거부"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"탭하여 배터리 세이버 예약"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_text (6324376061044218113) -->
-    <skip />
+    <string name="auto_saver_text" msgid="6324376061044218113">"배터리가 <xliff:g id="PERCENTAGE">%d</xliff:g>%%가 되면 자동으로 켜기"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"사용 안함"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"배터리 세이버 예약 사용 설정됨"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
-    <skip />
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"배터리가 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 아래로 내려가면 배터리 세이버가 자동으로 켜집니다."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"설정"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"확인"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index fc8a7d2..51cb1b1 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Байланыш оператору өзгөртүлүүдө"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Батареянын чоо-жайын ачуу"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Батарея <xliff:g id="NUMBER">%d</xliff:g> пайыз."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батарея кубатталууда, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> пайыз."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батарея кубатталууда, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Система тууралоолору."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Билдирмелер"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Бардык эскертмелерди көрүү"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Аты жок түзмөк"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Тышкы экранга чыгарууга даяр"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Жеткиликтүү түзмөктөр жок"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi туташкан жок"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Жарыктыгы"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Түстөрдү инверсиялоо"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> аккаунту менен кирди"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Интернет жок"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Чоо-жайын ачуу."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> себебине байланыштуу жеткиликсиз"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Жөндөөлөрдүн иретин өзгөртүү."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1b8adcc..d442258 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"​ອຸ​ປະ​ກອນບໍ່​ມີ​ຊື່"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"​ພ້ອ​ມ​ສົ່ງ​ສັນ​ຍານ​ແລ້ວ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"​ບໍ່​ມີ​ອຸ​ປະ​ກອນ​ທີ່​ສາ​ມາດ​ໃຊ້​ໄດ້"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ບໍ່ໄດ້ເຊື່ອມຕໍ່ Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ສະຫຼັບສີ"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"ເຂົ້າສູ່ລະບົບເປັນ <xliff:g id="ID_1">%s</xliff:g> ແລ້ວ"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ບໍ່ມີອິນເຕີເນັດ"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"ເປີດລາຍລະອຽດ."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"ບໍ່ສາມາດໃຊ້ໄດ້ເນື່ອງຈາກ <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2dccd89c..e26df8b2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -176,7 +176,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Keičiamas operatoriaus tinklas"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Atidaryti išsamią akumuliatoriaus informaciją"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Akumuliatorius: <xliff:g id="NUMBER">%d</xliff:g> proc."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Įkraunamas akumuliatorius, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> proc."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Įkraunamas akumuliatorius, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistemos nustatymai"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Pranešimai."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Žr. visus pranešimus"</string>
@@ -323,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Įrenginys be pavadinimo"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Paruošta perduoti"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nėra pasiekiamų įrenginių"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"„Wi-Fi“ neprijungtas"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Šviesumas"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Pakeisti spalvas"</string>
@@ -794,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prisijungta kaip <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nėra interneto ryšio"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Atidaryti išsamią informaciją."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nepasiekiama dėl <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Redaguoti nustatymų tvarką."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -866,10 +868,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Leisti"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Neleisti"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Palietę planuokite akumuliatoriaus tausojimo priemonės veikimą"</string>
-    <string name="auto_saver_text" msgid="6324376061044218113">"Įjunkite automatiškai akumuliatoriaus įkrovai pasiekus <xliff:g id="PERCENTAGE">%d</xliff:g> proc."</string>
+    <string name="auto_saver_text" msgid="6324376061044218113">"Įjunkite automatiškai akumuliatoriaus įkrovai pasiekus <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Ne, ačiū"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Akumuliatoriaus tausojimo priemonės veikimas suplanuotas"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Akumuliatoriaus tausojimo priemonė bus įjungta automatiškai akumuliatoriaus įkrovai pasiekus mažiau nei <xliff:g id="PERCENTAGE">%d</xliff:g> proc."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Akumuliatoriaus tausojimo priemonė bus įjungta automatiškai akumuliatoriaus įkrovai pasiekus mažiau nei <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Nustatymai"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"Supratau"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Pat. „SysUI“ krūvą"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 7c906ca..6f5e230 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -175,7 +175,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Mobilo sakaru operatora tīkla mainīšana"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Atvērt akumulatora informāciju"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Akumulators: <xliff:g id="NUMBER">%d</xliff:g> procenti"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Notiek akumulatora uzlāde, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procenti."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Notiek akumulatora uzlāde, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistēmas iestatījumi"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Paziņojumi"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Skatīt visus paziņojumus"</string>
@@ -321,6 +321,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nenosaukta ierīce"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gatavs apraidei"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nav pieejamu ierīču."</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Nav izveidots savienojums ar Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertēt krāsas"</string>
@@ -788,6 +789,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Pierakstījies kā <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nav piekļuves internetam"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Atvērt detalizēto informāciju."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nav pieejams šāda iemesla dēļ: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediģēt iestatījumu secību."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -860,14 +862,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Atļaut"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Neatļaut"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Pieskarieties, lai iestatītu akumulatora jaudas taupīšanas režīma grafiku"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_text (6324376061044218113) -->
-    <skip />
+    <string name="auto_saver_text" msgid="6324376061044218113">"Ieslēgt automātiski, kad akumulatora uzlādes līmenis ir <xliff:g id="PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Nē, paldies"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Ieslēgts akumulatora enerģijas taupīšanas režīma grafiks"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
-    <skip />
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Tiklīdz akumulatora uzlādes līmenis būs zemāks nekā <xliff:g id="PERCENTAGE">%d</xliff:g>%%, tiks automātiski ieslēgts akumulatora jaudas taupīšanas režīms."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Iestatījumi"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"Labi"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a5ffd0f..d13193b7 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Променување на мрежата на операторот"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Отвори ги деталите за батеријата"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Батерија <xliff:g id="NUMBER">%d</xliff:g> проценти."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Полнење на батеријата, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> проценти."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Полнење на батеријата, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Поставки на систем."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Известувања"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Видете ги сите известувања"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Неименуван уред"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Подготвено за емитување"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Нема достапни уреди"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi не е поврзано"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветленост"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Автоматски"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Преврти ги боите"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Најавени сте како <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Нема интернет"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Отворете ги деталите."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Недостапно бидејќи <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Уредете го редоследот на поставките."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 5abde4e..a5cad4e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"കാരിയർ നെറ്റ്‌വർക്ക് മാറ്റൽ"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"ബാറ്ററി വിശദാംശങ്ങൾ തുറക്കുക"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"ബാറ്ററി <xliff:g id="NUMBER">%d</xliff:g> ശതമാനം."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ബാറ്ററി ചാർജുചെയ്യുന്നു, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> ശതമാനം."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ബാറ്ററി ചാർജുചെയ്യുന്നു, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"സിസ്‌റ്റം ക്രമീകരണങ്ങൾ."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"അറിയിപ്പുകൾ."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"എല്ലാ അറിയിപ്പുകളും കാണുക"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"പേരിടാത്ത ഉപകരണം"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"കാസ്‌റ്റ് ചെയ്യാൻ തയ്യാറാണ്"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"വൈഫൈ കണക്റ്റ് ചെയ്‌തിട്ടില്ല"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"തെളിച്ചം"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"യാന്ത്രികം"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"നിറം മാറ്റുക"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"നിങ്ങളുടെ സ്ക്രീനിൽ പ്രദർശിപ്പിച്ചിരിക്കുന്ന എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ക്യാപ്‌ചർ ചെയ്യുന്നത് ആരംഭിക്കും."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"എല്ലാം മായ്‌ക്കുക"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"മാനേജ് ചെയ്യുക"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"\'ശല്യപ്പെടുത്തരുത്\' വഴി അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തി"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ആയി സൈൻ ഇൻ ചെയ്‌തു"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ഇന്റർനെറ്റ് ഇല്ല"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"വിശദാംശങ്ങൾ തുറക്കുക."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> എന്ന കാരണത്താൽ ലഭ്യമല്ല"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -858,7 +859,7 @@
     <string name="auto_saver_text" msgid="6324376061044218113">"ബാറ്ററി <xliff:g id="PERCENTAGE">%d</xliff:g>%% ആകുമ്പോൾ സ്വമേധയാ ഓണാക്കുക"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"വേണ്ട"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"ബാറ്ററി ലാഭിക്കൽ ഷെഡ്യൂൾ ഓണാക്കുക"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"ബാറ്ററി <xliff:g id="PERCENTAGE">%d</xliff:g>%%-ൽ താഴെയാകുമ്പോൾ, ബാറ്ററി ലാഭിക്കൽ സ്വമേധയാ ഓണാകും."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"ബാറ്ററി <xliff:g id="PERCENTAGE">%d</xliff:g>%% ൽ താഴെയാകുമ്പോൾ, ബാറ്ററി ലാഭിക്കൽ സ്വമേധയാ ഓണാകും."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"ക്രമീകരണം"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"മനസ്സിലായി"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"SysUI ഹീപ്പ് ഡമ്പ് ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 878e404..978fc0e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -172,7 +172,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Оператор компанийн сүлжээг өөрчилж байна"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Тэжээлийн дэлгэрэнгүй мэдээллийг нээх"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Батерей <xliff:g id="NUMBER">%d</xliff:g> хувьтай."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Тэжээлийг цэнэглэж байна, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> хувь."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батарейг цэнэглэж байна, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Системийн тохиргоо."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Мэдэгдэл."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Бүх мэдэгдлийг харах"</string>
@@ -317,6 +317,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Нэргүй төхөөрөмж"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Дамжуулахад бэлэн"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Төхөөрөмж байхгүй"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi-д холбогдоогүй байна"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Өнгийг урвуулах"</string>
@@ -780,6 +781,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g>-р нэвтэрсэн"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Интернэт алга"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Дэлгэрэнгүй мэдээллийг нээнэ үү."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>-н улмаас боломжгүй байна"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Тохиргооны дарааллыг өөрчилнө үү."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
@@ -852,10 +854,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Зөвшөөрөх"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Татгалзах"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Тэжээл хэмнэгч онцлогийг хуваарилахын тулд товших"</string>
-    <string name="auto_saver_text" msgid="6324376061044218113">"Батерей <xliff:g id="PERCENTAGE">%d</xliff:g>%% болох үед автоматаар асаах"</string>
+    <string name="auto_saver_text" msgid="6324376061044218113">"Батарей <xliff:g id="PERCENTAGE">%d</xliff:g>%% болох үед автоматаар асаах"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Үгүй, баярлалаа"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Тэжээл хэмнэгч онцлогийн хуваарийг асаасан"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Батерей <xliff:g id="PERCENTAGE">%d</xliff:g>%%-с бага болсон үед Тэжээл хэмнэгч онцлог автоматаар асна."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Батарей <xliff:g id="PERCENTAGE">%d</xliff:g>%%-с бага болсон үед Тэжээл хэмнэгч автоматаар асна."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Тохиргоо"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"Ойлголоо"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5a8e022..103ca46 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -57,7 +57,7 @@
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> अॅक्सेस करण्याची अनुमती द्यायची का?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> हाताळण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे का?"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> हाताळण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे का?"</string>
-    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इंस्टॉल केलेले अॅप्स या USB उपसाधनासह कार्य करत नाहीत. <xliff:g id="URL">%1$s</xliff:g> येथे या उपसाधनाविषयी अधिक जाणून घ्या"</string>
+    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इंस्टॉल केलेली अॅप्स या USB उपसाधनासह कार्य करत नाहीत. <xliff:g id="URL">%1$s</xliff:g> येथे या उपसाधनाविषयी अधिक जाणून घ्या"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB उपसाधन"</string>
     <string name="label_view" msgid="6304565553218192990">"पहा"</string>
     <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> कनेक्ट केलेली असताना नेहमी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडा"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"निनावी डिव्हाइस"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"कास्ट करण्यास तयार"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"कोणतेही डिव्हाइसेस उपलब्ध नाहीत"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"वाय-फाय कनेक्ट केलेले नाही"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"चमक"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वयंचलित"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"रंगांचा क्रम उलटा लावा"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपल्‍या स्‍क्रीनवर प्रदर्शित होणारी प्रत्‍येक गोष्‍ट कॅप्‍चर करणे प्रारंभ करेल."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"पुन्हा दर्शवू नका"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"सर्व साफ करा"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"व्यवस्थापित करा"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"व्यत्यय आणून नकाद्वारे सूचना थांबवल्या"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"आता सुरू करा"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"सूचना नाहीत"</string>
@@ -486,7 +486,7 @@
     <string name="monitoring_description_personal_profile_named_vpn" msgid="3133980926929069283">"तुमचे वैयक्तिक प्रोफाइल <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"तुमचे डिव्हाइस <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ने व्यवस्थापित केले आहे."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"तुमचे डिव्हाइस व्यवस्थापित करण्यासाठी <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> वापरते."</string>
-    <string name="monitoring_description_do_body" msgid="3639594537660975895">"आपला प्रशासक सेटिंग्ज, कॉर्पोरेट प्रवेश, अॅप्स, आपल्या डिव्हाइशी संबंधित डेटा आणि डिव्हाइसच्या स्थान माहितीचे निरीक्षण आणि व्यवस्थापन करू शकतो."</string>
+    <string name="monitoring_description_do_body" msgid="3639594537660975895">"तुमचा प्रशासक सेटिंग्ज, कॉर्पोरेट प्रवेश, अॅप्स, आपल्या डिव्हाइशी संबंधित डेटा आणि डिव्हाइसच्या स्थान माहितीचे निरीक्षण आणि व्यवस्थापन करू शकतो."</string>
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"अधिक जाणून घ्या"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"तुम्ही <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
@@ -496,7 +496,7 @@
     <string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"विश्वासू क्रेडेंशियल उघडा"</string>
     <string name="monitoring_description_network_logging" msgid="7223505523384076027">"आपल्या प्रशासकाने नेटवर्क लॉगिंग चालू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"तुम्ही VPN कनेक्शन सेट करण्यासाठी अ‍ॅपला परवानगी दिली.\n\nहा अ‍ॅप ईमेल, अ‍ॅप्स आणि वेबसाइटसह, तुमच्या डिव्हाइस आणि नेटवर्क अॅक्टिव्हिटीचे परीक्षण करू शकतो."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nआपला प्रशासक ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क अॅक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क अॅक्टिव्हिटीचे निरीक्षण करू शकते."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nतुमचा प्रशासक ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क अॅक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क अॅक्टिव्हिटीचे निरीक्षण करू शकते."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="1828472472674709532">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
@@ -577,8 +577,8 @@
     <string name="status_bar_airplane" msgid="7057575501472249002">"विमान मोड"</string>
     <string name="add_tile" msgid="2995389510240786221">"टाइल जोडा"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"प्रसारण टाइल"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"तुम्ही त्यापूर्वी हे बंद केल्याशिय आपला पुढील <xliff:g id="WHEN">%1$s</xliff:g> होणारा अलार्म ऐकणार नाही"</string>
-    <string name="zen_alarm_warning" msgid="444533119582244293">"तुम्ही आपला <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"तुम्ही त्यापूर्वी हे बंद केल्याशिय तुमचा पुढील <xliff:g id="WHEN">%1$s</xliff:g> होणारा अलार्म ऐकणार नाही"</string>
+    <string name="zen_alarm_warning" msgid="444533119582244293">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string>
     <string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g> वाजता"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"<xliff:g id="WHEN">%1$s</xliff:g> रोजी"</string>
     <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"द्रुत सेटिंग्ज, <xliff:g id="TITLE">%s</xliff:g>."</string>
@@ -598,7 +598,7 @@
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ सुरू करायचे?"</string>
-    <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड तुमच्या टॅबलेटसह कनेक्ट करण्यासाठी, तुम्ही प्रथम ब्लूटूथ चालू करणे आवश्यक आहे."</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"तुमचा कीबोर्ड तुमच्या टॅबलेटसह कनेक्ट करण्यासाठी, तुम्ही प्रथम ब्लूटूथ चालू करणे आवश्यक आहे."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
     <string name="show_silently" msgid="6841966539811264192">"सूचना शांतपणे दर्शवा"</string>
     <string name="block" msgid="2734508760962682611">"सर्व सूचना ब्लॉक करा"</string>
@@ -607,7 +607,7 @@
     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"पॉवर सूचना नियंत्रणे"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"चालू"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"बंद"</string>
-    <string name="power_notification_controls_description" msgid="4372459941671353358">"पॉवर सूचना नियंत्रणांच्या साहाय्याने तुम्ही अॅप सूचनांसाठी 0 ते 5 असे महत्त्व स्तर सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दाखवा \n- पूर्ण स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>\n" - पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा व्हायब्रेट करू नका \n\n"<b>"स्तर 1"</b>\n"- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा व्हायब्रेट करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना ब्लॉक करा"</string>
+    <string name="power_notification_controls_description" msgid="4372459941671353358">"पॉवर सूचना नियंत्रणांच्या साहाय्याने तुम्ही अॅप सूचनांसाठी 0 ते 5 असे महत्त्व स्तर सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दाखवा \n- फुल स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>\n" - फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा व्हायब्रेट करू नका \n\n"<b>"स्तर 1"</b>\n"- फुल स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा व्हायब्रेट करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना ब्लॉक करा"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"आता तुम्हाला या सूचना दिसणार नाहीत"</string>
     <string name="notification_channel_minimized" msgid="1664411570378910931">"या सूचना लहान केल्या जातील"</string>
@@ -754,16 +754,16 @@
   </string-array>
     <string name="other" msgid="4060683095962566764">"अन्य"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रीन विभाजक"</string>
-    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"डावी पूर्ण स्क्रीन"</string>
+    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"डावी फुल स्क्रीन"</string>
     <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"डावी 70%"</string>
     <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"डावी 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="543324403127069386">"डावी 30%"</string>
-    <string name="accessibility_action_divider_right_full" msgid="4639381073802030463">"उजवी पूर्ण स्क्रीन"</string>
-    <string name="accessibility_action_divider_top_full" msgid="5357010904067731654">"शीर्ष पूर्ण स्क्रीन"</string>
+    <string name="accessibility_action_divider_right_full" msgid="4639381073802030463">"उजवी फुल स्क्रीन"</string>
+    <string name="accessibility_action_divider_top_full" msgid="5357010904067731654">"शीर्ष फुल स्क्रीन"</string>
     <string name="accessibility_action_divider_top_70" msgid="5090779195650364522">"शीर्ष 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="6385859741925078668">"शीर्ष 50%"</string>
     <string name="accessibility_action_divider_top_30" msgid="6201455163864841205">"शीर्ष 10"</string>
-    <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"तळाशी पूर्ण स्क्रीन"</string>
+    <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"तळाशी फुल स्क्रीन"</string>
     <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करण्यासाठी दोनदा टॅप करा."</string>
     <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> . जोडण्यासाठी दोनदा टॅप करा."</string>
     <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> हलवा"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> म्हणून साइन इन केले"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"इंटरनेट नाही"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"तपशील उघडा."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> मुळे उपलब्ध नाही"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग्जचा क्रम संपादित करा."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
@@ -800,11 +801,11 @@
     <string name="pip_skip_to_next" msgid="1948440006726306284">"डावलून पुढे जा"</string>
     <string name="pip_skip_to_prev" msgid="1955311326688637914">"डावलून मागे जा"</string>
     <string name="thermal_shutdown_title" msgid="4458304833443861111">"तापल्‍यामुळे फोन बंद झाला"</string>
-    <string name="thermal_shutdown_message" msgid="9006456746902370523">"आपला फोन आता व्‍यवस्थित चालू आहे"</string>
-    <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"आपला फोन खूप तापलाय, म्हणून तो थंड होण्यासाठी बंद झाला आहे. आपला फोन आता व्‍यवस्थित चालू आहे.\n\nतुम्ही असे केल्यास आपला फोन खूप तापेल:\n	•संसाधन केंद्रित अॅप वापरणे (गेमिंग, व्हिडिओ किंवा नेव्हिगेशन अॅप यासारखे)\n	•मोठ्या फायली डाउनलोड किंवा अपलोड करणे\n	•उच्च तापमानामध्ये आपला फोन वापरणे"</string>
+    <string name="thermal_shutdown_message" msgid="9006456746902370523">"तुमचा फोन आता व्‍यवस्थित चालू आहे"</string>
+    <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"तुमचा फोन खूप तापलाय, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा फोन आता व्‍यवस्थित चालू आहे.\n\nतुम्ही असे केल्यास तुमचा फोन खूप तापेल:\n	•संसाधन केंद्रित अॅप वापरणे (गेमिंग, व्हिडिओ किंवा नेव्हिगेशन अॅप यासारखे)\n	•मोठ्या फायली डाउनलोड किंवा अपलोड करणे\n	•उच्च तापमानामध्ये तुमचा फोन वापरणे"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"फोन ऊष्ण होत आहे"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"फोन थंड होत असताना काही वैशिष्‍ट्ये मर्यादित असतात"</string>
-    <string name="high_temp_dialog_message" msgid="6840700639374113553">"आपला फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही आपला फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nआपला फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
+    <string name="high_temp_dialog_message" msgid="6840700639374113553">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
     <string name="lockscreen_shortcut_left" msgid="2182769107618938629">"डावा शॉर्टकट"</string>
     <string name="lockscreen_shortcut_right" msgid="3328683699505226536">"उजवा शॉर्टकट"</string>
     <string name="lockscreen_unlock_left" msgid="2043092136246951985">"डावा शॉर्टकट देखील अनलॉक करतो"</string>
diff --git a/packages/SystemUI/res/values-mr/strings_tv.xml b/packages/SystemUI/res/values-mr/strings_tv.xml
index aac2d5e..8ed1558 100644
--- a/packages/SystemUI/res/values-mr/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr/strings_tv.xml
@@ -22,5 +22,5 @@
     <string name="notification_channel_tv_pip" msgid="134047986446577723">"चित्रा-मध्‍ये-चित्र"</string>
     <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(शीर्षक नसलेला कार्यक्रम)"</string>
     <string name="pip_close" msgid="3480680679023423574">"PIP बंद करा"</string>
-    <string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रीन"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"फुल स्क्रीन"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e6f7abb..7a6a1e3 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Peranti tidak bernama"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Bersedia untuk menghantar"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Tiada peranti tersedia"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi tidak disambungkan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Terbalikkan warna"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Dilog masuk sebagai <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Tiada Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Buka butiran."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Tidak tersedia disebabkan <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit susunan tetapan."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 1103b3c..62970aa 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"ဝန်ဆောင်မှုပေးသူ ကွန်ရက် ပြောင်းလဲနေသည်။"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"ဘက်ထရီ အသေးစိတ် အချက်အလက်များကို ဖွင့်ပါ"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"ဘတ္တရီ <xliff:g id="NUMBER">%d</xliff:g> ရာခိုင်နှုန်း။"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ဘက်ထရီအားသွင်းနေသည်၊ <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> ရာခိုင်နှုန်း။"</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ဘက်ထရီအားသွင်းနေသည်၊ <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%။"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"စနစ်အပြင်အဆင်များ"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"အကြောင်းကြားချက်များ။"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"သတိပေးချက်များအားလုံးကို ကြည့်ရန်"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"အမည်မတပ် ကိရိယာ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ကာစ်တ် လုပ်ရန် အသင့် ရှိနေပြီ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"ကိရိယာများ မရှိ"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi ချိတ်ဆက်ထားခြင်းမရှိပါ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"အလင်းတောက်ပမှု"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"အလိုအလျောက်"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"အရောင်များ ပြောင်းပြန်လုပ်ရန်"</string>
@@ -605,7 +606,7 @@
     <string name="do_not_silence_block" msgid="4070647971382232311">"အသံ မတိတ်ပါနှင့် သို့မဟုတ် မပိတ်ဆို့ပါနှင့်"</string>
     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"ပါဝါအကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ဖွင့်ပါ"</string>
-    <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ပိတ်ပါ"</string>
+    <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ပိတ်ထားသည်"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ပါဝါအကြောင်းကြားချက် ထိန်းချုပ်မှုများကိုအသုံးပြုပြီး အက်ပ်တစ်ခု၏ အကြောင်းကြားချက် အရေးပါမှု ၀ မှ ၅ အထိသတ်မှတ်ပေးနိုင်သည်။ \n\n"<b>"အဆင့် ၅"</b>" \n- အကြောင်းကြားချက်စာရင်း၏ ထိပ်ဆုံးတွင် ပြသည် \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်းကို ခွင့်ပြုသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၄"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၃"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n\n"<b>"အဆင့် ၂"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n\n"<b>"အဆင့် ၁"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n- လော့ခ်ချထားသည့် မျက်နှာပြင်နှင့် အခြေအနေဘားတန်းတို့တွင် မပြပါ \n- အကြောင်းကြားချက်စာရင်း အောက်ဆုံးတွင်ပြသည် \n\n"<b>"အဆင့် ၀"</b>" \n- အက်ပ်မှ အကြောင်းကြားချက်များ အားလုံးကို ပိတ်ဆို့သည်"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"အကြောင်းကြားချက်များ"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ဤအကြောင်းကြားချက်များကို မြင်ရတော့မည် မဟုတ်ပါ"</string>
@@ -707,7 +708,7 @@
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ဒေတာချွေတာမှု ဖွင့်ထားသည်"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ဒေတာချွေတာမှု ပိတ်ထားသည်"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ဖွင့်ပါ"</string>
-    <string name="switch_bar_off" msgid="8803270596930432874">"ပိတ်ပါ"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ပိတ်ထားသည်"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ရွှေ့လျားရန်ဘားတန်း"</string>
     <string name="nav_bar_layout" msgid="3664072994198772020">"အပြင်အဆင်"</string>
     <string name="left_nav_bar_button_type" msgid="8555981238887546528">"လက်ဝဲခလုတ် အမျိုးအစားအပို"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> အဖြစ် လက်မှတ်ထိုးဝင်ထားသည်။"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"အင်တာနက် မရှိပါ"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"အသေးစိတ်များကို ဖွင့်ပါ။"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> ကြောင့် မရနိုင်ပါ"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5db7a3c..81ff8e2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Enhet uten navn"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Klar til å caste"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Ingen enheter er tilgjengelige"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi er ikke tilkoblet"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter farger"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Logget på som <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Ingen Internett-tilkobling"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Åpne informasjonen."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Utilgjengelig fordi <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Endre rekkefølgen på innstillingene."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e77c5cd..4f2845e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"बेनाम उपकरण"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"प्रसारण गर्न तयार"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"कुनै उपकरणहरू उपलब्ध छैन"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi जडान गरिएको छैन"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"उज्यालपन"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वतः"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"रंग उल्टाउनुहोस्"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> को रूपमा साइन इन गरियो"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"इन्टरनेट छैन"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"विवरणहरूलाई खोल्नुहोस्।"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> का कारण उपलब्ध छैन"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 58d7949..60ca532 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Netwerk van provider wordt gewijzigd"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Accudetails openen"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batterij: <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batterij wordt opgeladen, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procent."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batterij wordt opgeladen, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%% procent."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systeeminstellingen."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Meldingen."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Alle meldingen bekijken"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Naamloos apparaat"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Klaar om te casten"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Geen apparaten beschikbaar"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wifi niet verbonden"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Kleuren omkeren"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Ingelogd als <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Geen internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Details openen."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Niet beschikbaar vanwege <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 9f4cedf..a78f5cd 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ନାମହୀନ ଡିଭାଇସ୍‍"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"କାଷ୍ଟ୍ ପାଇଁ ପ୍ରସ୍ତୁତ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ୱାଇ-ଫାଇ ସଂଯୋଜିତ ହୋଇନାହିଁ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ଉଜ୍ଜ୍ୱଳତା"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ସ୍ୱଚାଳିତ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ରଙ୍ଗ ପୂର୍ବପରି କରନ୍ତୁ"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ଭାବରେ ସାଇନ୍‌ ଇନ୍‌ କରିଛନ୍ତି"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"କୌଣସି ଇଣ୍ଟରନେଟ୍‌ କନେକ୍ସନ୍ ନାହିଁ"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"ବିବରଣୀ ଖୋଲନ୍ତୁ"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> ଯୋଗୁଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ସେଟିଙ୍ଗର କ୍ରମ ସଂଶୋଧନ କରନ୍ତୁ।"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ପୃଷ୍ଠା <xliff:g id="ID_1">%1$d</xliff:g> ମୋଟ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 5a1fff4..7e9a916 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ਬਿਨਾਂ ਨਾਮ ਦਾ ਡੀਵਾਈਸ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ਜੋੜਨ ਲਈ ਤਿਆਰ"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"ਕੋਈ ਡਿਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ਵਾਈ-ਫਾਈ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ਚਮਕ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ਆਟੋ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ਰੰਗ ਉਲਟੋ"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਉਹ ਸਭ ਕੁਝ ਕੈਪਚਰ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰ ਦੇਵੇਗਾ, ਜੋ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਤੇ ਡਿਸਪਲੇ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ਹੁਣ ਚਾਲੂ ਕਰੋ"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ਕੋਈ ਸੂਚਨਾਵਾਂ ਨਹੀਂ"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ਵਜੋਂ ਸਾਈਨ ਇਨ ਕੀਤਾ"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ।"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"ਵੇਰਵੇ ਖੋਲ੍ਹੋ।"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> ਦੇ ਕਾਰਨ ਅਣਉਪਲਬਧ ਹੈ"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 41bac38..22ef98c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -323,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Urządzenie bez nazwy"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gotowy do działania"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Brak dostępnych urządzeń"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Brak połączenia z Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Odwróć kolory"</string>
@@ -794,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Jesteś zalogowany jako <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Brak internetu"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otwórz szczegóły."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Niedostępne z powodu: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4c0df134..f26d1ba 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Alteração de rede da operadora"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir detalhes da bateria"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Bateria em <xliff:g id="NUMBER">%d</xliff:g> por cento."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Bateria carregando: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Configurações do sistema"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificações."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Ver todas as notificações"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto para transmitir"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Não há dispositivos disponíveis"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi não conectado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Login efetuado como <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Sem Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Abrir detalhes."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Indisponível devido a <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 81be3f6..e6ed4dc 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto para transmitir"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Sem dispositivos disponíveis"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi não ligado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Sessão iniciada como <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Sem Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Abrir os detalhes."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Indisponível devido a <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a ordem das definições."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4c0df134..f26d1ba 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Alteração de rede da operadora"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir detalhes da bateria"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Bateria em <xliff:g id="NUMBER">%d</xliff:g> por cento."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Bateria carregando: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Configurações do sistema"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificações."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Ver todas as notificações"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto para transmitir"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Não há dispositivos disponíveis"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi não conectado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Login efetuado como <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Sem Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Abrir detalhes."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Indisponível devido a <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index b5bd02d5..c553f6e 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -175,9 +175,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Se schimbă rețeaua operatorului"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Deschideți detaliile privind bateria"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterie: <xliff:g id="NUMBER">%d</xliff:g> la sută."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Se încarcă bateria, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Setări de sistem."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificări."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Vedeți toate notificările"</string>
@@ -323,6 +321,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispozitiv nedenumit"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pregătit pentru proiecție"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Niciun dispozitiv disponibil"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Rețeaua Wi-Fi nu este conectată"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inversați culorile"</string>
@@ -790,6 +789,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Conectat(ă) ca <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Fără conexiune la internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Deschideți detaliile."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Indisponibile deoarece <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editați ordinea setărilor."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 23324a21..07aa66a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -176,9 +176,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Сменить сеть"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Сведения о расходе заряда батареи"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Заряд батареи в процентах: <xliff:g id="NUMBER">%d</xliff:g>."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Зарядка батареи. Текущий заряд: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Настройки"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Уведомления"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Показать все уведомления"</string>
@@ -325,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Безымянное устройство"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово к передаче"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Нет доступных устройств"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Нет подключения к сети Wi-Fi."</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Обратные цвета"</string>
@@ -796,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Выполнен вход под именем <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Нет подключения к Интернету."</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Показать подробности."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Недоступно. <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Изменить порядок быстрых настроек."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -868,14 +868,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Да"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Нет"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Нажмите, чтобы настроить режим энергосбережения"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_text (6324376061044218113) -->
-    <skip />
+    <string name="auto_saver_text" msgid="6324376061044218113">"Включать автоматически при заряде батареи ниже <xliff:g id="PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Отмена"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Автоматический переход в режим энергосбережения включен"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
-    <skip />
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Режим энергосбережения активируется при заряде батареи ниже <xliff:g id="PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Открыть настройки"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"ОК"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Передача SysUI"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 98b79be..aac62a2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"වාහක ජාලය වෙනස් වෙමින්"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"බැටරි විස්තර විවෘත කරන්න"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"බැටරි ප්‍රතිශතය <xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"බැටරිය ආරෝපණය කරමින්, සියයට <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"බැටරිය ආරෝපණය කරමින්, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"පද්ධති සැකසීම්."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"දැනුම්දීම්."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"සියලු දැනුම්දීම් බලන්න"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"නම් නොකළ උපාංගය"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"කාස්ට් කිරීමට සුදානම්"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"උපාංග නොතිබේ"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi සම්බන්ධ නොවීය"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"දීප්තිමත් බව"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ස්වයංක්‍රීය"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"වර්ණ යටිකුරු කරන්න"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> ලෙස පුරන්න"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"අන්තර්ජාලය නැත"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"විස්තර විවෘත කරන්න."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> හේතුවෙන් ලබා ගත නොහැකිය"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d871cb4..58e176a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -176,9 +176,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Mení sa sieť operátora"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Otvoriť podrobnosti o batérii"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batéria <xliff:g id="NUMBER">%d</xliff:g> percent."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Nabíja sa batéria, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Nastavenia systému."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Upozornenia."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Zobraziť všetky upozornenia"</string>
@@ -325,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nepomenované zariadenie"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pripravené na prenášanie"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nie sú k dispozícii žiadne zariadenia"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Sieť Wi‑Fi nie je pripojená"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverzia farieb"</string>
@@ -796,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prihlásený používateľ <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Žiadny internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otvoriť podrobnosti"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nedostupné z nasledujúceho dôvodu: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upraviť poradie nastavení"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e8f04af..1323fcd 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -176,9 +176,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Spreminjanje omrežja operaterja"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Odpiranje podrobnosti o akumulatorju"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija <xliff:g id="NUMBER">%d</xliff:g> odstotkov."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Polnjenje akumulatorja, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistemske nastavitve."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obvestila."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Prikaži vsa obvestila"</string>
@@ -325,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovana naprava"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pripravljeno za predvajanje"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Na voljo ni nobene naprave"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Povezava Wi-Fi ni vzpostavljena"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Obrni barve"</string>
@@ -796,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prijavljeni ste kot <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Brez internetne povezave"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Odpri podrobnosti."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Ni na voljo zaradi tega razloga: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uredi vrstni red nastavitev."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -868,14 +868,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Dovoli"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Zavrni"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Dotaknite se za načrtovanje varčevanja z energijo akumulatorja"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_text (6324376061044218113) -->
-    <skip />
+    <string name="auto_saver_text" msgid="6324376061044218113">"Samodejno vklopi, ko je energija akumulatorja na <xliff:g id="PERCENTAGE">%d</xliff:g> %%"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Ne, hvala"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Urnik varčevanja z energijo akumulatorja je vklopljen"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for auto_saver_enabled_text (874711029884777579) -->
-    <skip />
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Varčevanje z energijo akumulatorja se bo samodejno vklopilo, ko bo energija akumulatorja pod <xliff:g id="PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Nastavitve"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"V redu"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Izvoz kopice SysUI"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 429e84d..8f08665 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Rrjeti i operatorit celular po ndryshohet"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Hap detajet e baterisë"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Bateria ka edhe <xliff:g id="NUMBER">%d</xliff:g> për qind."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Bateria po ngarkohet, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> për qind."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Bateria po ngarkohet, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Cilësimet e sistemit."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Njoftimet."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Shiko të gjitha njoftimet"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Pajisje e paemërtuar"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gati për transmetim"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nuk ofrohet për përdorim asnjë pajisje"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi nuk është lidhur"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ndriçimi"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Automatike"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Shkëmbe ngjyrat"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Identifikuar si <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Nuk ka internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Hap detajet."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Nuk ofrohet për shkak se <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifiko rendin e cilësimeve."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index a164876..609f332 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -175,7 +175,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Промена мреже мобилног оператера"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Отвори детаље о батерији"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Батерија је на <xliff:g id="NUMBER">%d</xliff:g> посто."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батерија се пуни, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> процената."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Батерија се пуни, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Системска подешавања."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Обавештења."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Погледајте сва обавештења"</string>
@@ -321,6 +321,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Неименовани уређај"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Спремно за пребацивање"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Није доступан ниједан уређај"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi није повезан"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Обрни боје"</string>
@@ -788,6 +789,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Пријављени сте као <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Нема интернета"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Отвори детаље."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Није доступно из следећег разлога: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Измени редослед подешавања."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 37614d9..72ae99b 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Namnlös enhet"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Redo att casta"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Inga tillgängliga enheter"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Inte ansluten till Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertera färger"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Inloggad som <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Inget internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Visa information."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Inte tillgänglig på grund av <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ändra ordning på inställningarna."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5cbd2db..a73d0e7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Kifaa hakina jina"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Tayari kutuma"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Hakuna vifaa vilivyopatikana"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi haijaunganishwa"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Pindua rangi"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Umeingia katika akaunti ya <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Hakuna intaneti"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Fungua maelezo."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Haipatikani kutokana na <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Badilisha orodha ya mipangilio."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 1f498e6..02457d9 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"பெயரிடப்படாத சாதனம்"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"திரையிடத் தயார்"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"சாதனங்கள் இல்லை"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"வைஃபை இணைக்கப்படவில்லை"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ஒளிர்வு"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"தானியங்கு"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"வண்ணங்களை மாற்று"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"திரையில் காட்டப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> படமெடுக்கும்."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"மீண்டும் காட்டாதே"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"எல்லாவற்றையும் அழி"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"அறிவிப்புகளை நிர்வகி"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"இப்போது தொடங்கு"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"அறிவிப்புகள் இல்லை"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> என்ற பெயரில் உள்நுழைந்துள்ளீர்கள்"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"இணைய இணைப்பு இல்லை"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"விவரங்களைத் திற."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> என்பதால் தற்போது முடக்கப்பட்டுள்ளது"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 6c8f728d3..a6d7699 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"క్యారియర్ నెట్‌వర్క్ మారుతోంది"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"బ్యాటరీ వివరాలను తెరుస్తుంది"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"బ్యాటరీ <xliff:g id="NUMBER">%d</xliff:g> శాతం."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"బ్యాటరీ ఛార్జ్ అవుతోంది, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> శాతం."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"బ్యాటరీ ఛార్జ్ అవుతోంది, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"సిస్టమ్ సెట్టింగ్‌లు."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"నోటిఫికేషన్‌లు."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"అన్ని నోటిఫికేషన్‌లను చూడండి"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"పేరులేని పరికరం"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ప్రసారం చేయడానికి సిద్ధంగా ఉంది"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi కనెక్ట్ కాలేదు"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ప్రకాశం"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"స్వయంచాలకం"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"రంగులను తారుమారు చేయి"</string>
@@ -442,8 +443,7 @@
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> మీ స్క్రీన్‌పై కనిపించే ప్రతిదాన్ని క్యాప్చర్ చేయడం ప్రారంభిస్తుంది."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"మళ్లీ చూపవద్దు"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"అన్నీ క్లియర్ చేయండి"</string>
-    <!-- no translation found for manage_notifications_text (2386728145475108753) -->
-    <skip />
+    <string name="manage_notifications_text" msgid="2386728145475108753">"నిర్వహించండి"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"అంతరాయం కలిగించవద్దు ద్వారా నోటిఫికేషన్‌లు పాజ్ చేయబడ్డాయి"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ఇప్పుడే ప్రారంభించు"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"నోటిఫికేషన్‌లు లేవు"</string>
@@ -783,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> వలె సైన్ ఇన్ చేసారు"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ఇంటర్నెట్ లేదు"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"వివరాలను తెరవండి."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> కారణంగా అందుబాటులో లేదు"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్‌లను తెరవండి."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"సెట్టింగ్‌ల క్రమాన్ని సవరించండి."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d72d2d6..8c78687 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"อุปกรณ์ที่ไม่มีชื่อ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"พร้อมที่จะส่ง"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"ไม่มีอุปกรณ์ที่สามารถใช้ได้"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"ไม่ได้เชื่อมต่อ Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"สลับสี"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"ลงชื่อเข้าใช้เป็น <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"เปิดรายละเอียด"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"ไม่พร้อมใช้งานเนื่องจาก<xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"แก้ไขลำดับการตั้งค่า"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c67aca4..21cf1f2 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Walang pangalang device"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Handang mag-cast"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Walang available na mga device"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Hindi nakakonekta sa Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"I-invert ang mga kulay"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Naka-sign in bilang <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Walang internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Buksan ang mga detalye."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Hindi available dahil sa <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index edb9262..fb200ec 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Adsız cihaz"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Yayın için hazır"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Kullanılabilir cihaz yok"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Kablosuz ağ bağlı değil"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Renkleri çevir"</string>
@@ -372,7 +373,7 @@
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranı sola doğru böl"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranı sağa doğru böl"</string>
     <string name="quick_step_accessibility_toggle_overview" msgid="7171470775439860480">"Genel bakışı aç/kapat"</string>
-    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Şarj oldu"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Şarj oluyor"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Tam şarj olmasına <xliff:g id="CHARGING_TIME">%s</xliff:g> kaldı"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Şarj olmuyor"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> olarak oturum açıldı"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"İnternet yok"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Ayrıntıları aç."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> nedeniyle kullanılamıyor"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sırasını düzenle."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 3d82520..82b56a2 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -176,9 +176,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Змінення мережі оператора"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Відкрити деталі акумулятора"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Заряд акумулятора у відсотках: <xliff:g id="NUMBER">%d</xliff:g>."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Акумулятор заряджається: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Налаштування системи."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Сповіщення."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Переглянути всі сповіщення"</string>
@@ -325,6 +323,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Пристрій без назви"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово до трансляції"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Немає пристроїв"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi не під’єднано"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Інвертувати кольори"</string>
@@ -796,6 +795,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Ви ввійшли як <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Немає Інтернету"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Відкрити деталі."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Недоступно, оскільки <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змінити порядок налаштувань."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
@@ -868,10 +868,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Дозволити"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Відмовити"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Торкніться, щоб увімкнути автоматичний режим економії заряду акумулятора"</string>
-    <string name="auto_saver_text" msgid="6324376061044218113">"Вмикати автоматично, коли рівень знижується до <xliff:g id="PERCENTAGE">%d</xliff:g>%%"</string>
+    <string name="auto_saver_text" msgid="6324376061044218113">"Вмикати автоматично, коли заряд акумулятора знижується до <xliff:g id="PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Ні, дякую"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Автоматичний режим економії заряду акумулятора ввімкнено"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Режим економії заряду акумулятора вмикатиметься автоматично, коли рівень нижчий за <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Режим економії заряду акумулятора вмикається автоматично, коли рівень заряду нижчий за <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Налаштування"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"OK"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 6b9c737..b02ceae 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"کیریئر نیٹ ورک کی تبدیلی"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"بیٹری کی تفصیلات کھولیں"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"بیٹری <xliff:g id="NUMBER">%d</xliff:g> فیصد۔"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"بیٹری چارجنگ، <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> فیصد۔"</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"بیٹری چارج ہو رہی ہے، <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"سسٹم کی ترتیبات۔"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"اطلاعات۔"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"تمام اطلاعات دیکھیں"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"بغیر نام والا آلہ"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"کاسٹ کرنے کیلئے تیار"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"کوئی آلات دستیاب نہیں ہیں"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"‏Wi-Fi سے منسلک نہیں ہے"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"چمکیلا پن"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"رنگ پلٹیں"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> کے بطور سائن ان ہے"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"انٹرنیٹ نہیں ہے"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"تفصیلات کھولیں۔"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g> کی وجہ سے دستیاب نہیں ہے"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index e2b5df4..a128e7f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -127,7 +127,7 @@
     <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Ma’lumotlar bitta panelda."</string>
     <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Ma’lumotlar ikkita panelda."</string>
     <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Ma’lumotlar uchta panelda."</string>
-    <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Ma’lumot uzatish signali to‘liq."</string>
+    <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Internet signali butun."</string>
     <string name="accessibility_wifi_name" msgid="7202151365171148501">"Ulangan: <xliff:g id="WIFI">%s</xliff:g>."</string>
     <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Ulangan: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="4026393061247081201">"Bunga ulangan: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Mobil tarmoqni o‘zgartirish"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Batareya quvvati sarfi haqida ma’lumot"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batareya <xliff:g id="NUMBER">%d</xliff:g> foiz."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batareya quvvat olmoqda (<xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%)."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Tizim sozlamalari."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Eslatmalar."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Barcha bildirishnomalarni ko‘rish"</string>
@@ -300,7 +298,7 @@
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Eniga"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Kiritish usuli"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Joylashuv"</string>
-    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Joylashuv xizmati o‘chiq"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Media qurilma"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Favqulodda chaqiruvlar"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nomsiz qurilma"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Tarqatish uchun tayyor"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Qurilmalar topilmadi"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi-Fi tarmoqqa ulanmagan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Yorqinlik"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AVTOMATIC"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Teskari ranglar"</string>
@@ -782,8 +781,9 @@
     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Tezkor sozlamalarni yopish."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Signal o‘rnatildi."</string>
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"<xliff:g id="ID_1">%s</xliff:g> sifatida kirgansiz"</string>
-    <string name="data_connection_no_internet" msgid="4503302451650972989">"Internetga ulanmagan"</string>
+    <string name="data_connection_no_internet" msgid="4503302451650972989">"Internetga ulanmagansiz"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Tafsilotlarini ko‘rsatish."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Mavjud emas, sababi: <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Sozlamalar tartibini o‘zgartirish."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
@@ -856,10 +856,10 @@
     <string name="slice_permission_allow" msgid="2340244901366722709">"Ruxsat"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Rad etish"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Quvvat tejash rejimini rejalashtirish uchun bosing"</string>
-    <string name="auto_saver_text" msgid="6324376061044218113">"Batareya quvvati <xliff:g id="PERCENTAGE">%d</xliff:g>%% ga tushganda avtomatik yoqish"</string>
+    <string name="auto_saver_text" msgid="6324376061044218113">"Batareya quvvati <xliff:g id="PERCENTAGE">%d</xliff:g>%% ga tushganida avtomatik yoqish"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Kerak emas"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Quvvat tejash rejimi jadvali faollashtirildi"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Batareya quvvati <xliff:g id="PERCENTAGE">%d</xliff:g>%% ga tushganda, quvvat tejash rejimi avtomatik ravishda yoqiladi."</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"Batareya quvvati <xliff:g id="PERCENTAGE">%d</xliff:g>%% ga tushsa, quvvat tejash rejimi avtomatik ravishda yoqiladi."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Sozlamalar"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"OK"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8f98557..c7b9178 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Thay đổi mạng của nhà mạng"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Mở chi tiết về pin"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> phần trăm pin."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Đang sạc pin, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> phần trăm."</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Đang sạc pin, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Cài đặt hệ thống"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Thông báo."</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"Xem tất cả thông báo"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Thiết bị không có tên"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Sẵn sàng truyền"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Không có thiết bị nào"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Chưa kết nối với Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Đảo ngược màu"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Đã đăng nhập là <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Không có Internet"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Mở chi tiết."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Không sử dụng được do <xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Chỉnh sửa thứ tự cài đặt."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 27cad95..0bfcdcf 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"运营商网络正在更改"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"打开电量详情"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"电池电量为百分之 <xliff:g id="NUMBER">%d</xliff:g>。"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"正在充电,已完成百分之<xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>。"</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"正在充电,已完成 <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%。"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"系统设置。"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"通知。"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"查看所有通知"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名设备"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"已准备好投射"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"没有可用设备"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"未连接到 WLAN 网络"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"反色"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"目前登录的用户名为<xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"未连接到互联网"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"打开详情页面。"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>,因此目前无法使用"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"修改设置顺序。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index da768b6..cf93802 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -174,9 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"流動網絡供應商網絡正在變更"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"開啟電池詳細資料"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"電池電量為百分之 <xliff:g id="NUMBER">%d</xliff:g>。"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
-    <skip />
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"正在充電:<xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%。"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"系統設定"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"通知。"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"睇所有通知"</string>
@@ -321,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名的裝置"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"放送準備完成"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"沒有可用裝置"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"未連線至 Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"反轉顏色"</string>
@@ -784,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"已登入為<xliff:g id="ID_1">%s</xliff:g>。"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"沒有互聯網連線"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"開啟詳細資料頁面。"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>,所以宜家用唔到"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定次序。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 116f98b..c5a2f90 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -174,7 +174,7 @@
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"電信業者網路正在進行變更"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"開啟電量詳細資料"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"電池電量為百分之 <xliff:g id="NUMBER">%d</xliff:g>。"</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"充電中,已完成百分之 <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>。"</string>
+    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"充電中,已完成 <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%。"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"系統設定"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"通知。"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"查看所有通知"</string>
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名的裝置"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"可以開始投放了"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"沒有可用裝置"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"未連線至 Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"反轉顏色"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"以「<xliff:g id="ID_1">%s</xliff:g>」的身分登入"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"沒有網際網路連線"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"開啟詳細資料。"</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"<xliff:g id="REASON">%s</xliff:g>,因此目前無法使用"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定順序。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 53d3b9c..2fc207a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -319,6 +319,7 @@
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Idivayisi engenalo igama"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ilungele ukusakaza"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Ayikho idivayisi etholakalayo"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"I-Wi-Fi ayixhunyiwe"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Faka imibala"</string>
@@ -782,6 +783,7 @@
     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Ungene ngemvume njengo-<xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="4503302451650972989">"Ayikho i-inthanethi"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Vula imininingwane."</string>
+    <string name="accessibility_quick_settings_not_available" msgid="4190068184294019846">"Ayitholakali ngenxa ye-<xliff:g id="REASON">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Hlela uhlelo lwezilungiselelo."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
index 19e8673..114d69e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
@@ -27,6 +27,7 @@
 /**
  * Background task resource loader
  */
+@Deprecated
 class BackgroundTaskLoader implements Runnable {
     static String TAG = "BackgroundTaskLoader";
     static boolean DEBUG = false;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
index 898d64a..7e0f8fe2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
@@ -27,6 +27,7 @@
 /**
  * A list of filtered tasks.
  */
+@Deprecated
 class FilteredTaskList {
 
     private final ArrayList<Task> mTasks = new ArrayList<>();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
index 852463f..f02bc5a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
@@ -34,6 +34,7 @@
 /**
  * Loader class that loads full-resolution thumbnails when appropriate.
  */
+@Deprecated
 public class HighResThumbnailLoader implements
         TaskCallbacks, BackgroundTaskLoader.OnIdleChangedListener {
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index f69e911..8b3ae42 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -45,6 +45,7 @@
  *   3) executePlan() will actually load and fill in the icons and thumbnails according to the load
  *      options specified, such that we can transition into the Recents activity seamlessly
  */
+@Deprecated
 public class RecentsTaskLoadPlan {
 
     /** The set of conditions to preload tasks. */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index 996c837..b50aa76 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -42,6 +42,7 @@
 /**
  * Recents task loader
  */
+@Deprecated
 public class RecentsTaskLoader {
     private static final String TAG = "RecentsTaskLoader";
     private static final boolean DEBUG = false;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index b51004b..368e503 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shared.recents.model;
 
+import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -31,13 +32,14 @@
 import java.util.Objects;
 
 /**
- * A task represents the top most task in the system's task stack.
+ * A task in the recent tasks list.
  */
 public class Task {
 
     public static final String TAG = "Task";
 
     /* Task callbacks */
+    @Deprecated
     public interface TaskCallbacks {
         /* Notifies when a task has been bound */
         void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
@@ -65,6 +67,21 @@
 
         private int mHashCode;
 
+        public TaskKey(ActivityManager.RecentTaskInfo t) {
+            ComponentName sourceComponent = t.origActivity != null
+                    // Activity alias if there is one
+                    ? t.origActivity
+                    // The real activity if there is no alias (or the target if there is one)
+                    : t.realActivity;
+            this.id = t.taskId;
+            this.windowingMode = t.configuration.windowConfiguration.getWindowingMode();
+            this.baseIntent = t.baseIntent;
+            this.sourceComponent = sourceComponent;
+            this.userId = t.userId;
+            this.lastActiveTime = t.lastActiveTime;
+            updateHashCode();
+        }
+
         public TaskKey(int id, int windowingMode, Intent intent,
                 ComponentName sourceComponent, int userId, long lastActiveTime) {
             this.id = id;
@@ -125,7 +142,8 @@
     /**
      * The temporary sort index in the stack, used when ordering the stack.
      */
-    public int temporarySortIndexInStack;
+    @Deprecated
+    int temporarySortIndexInStack;
 
     /**
      * The icon is the task description icon (if provided), which falls back to the activity icon,
@@ -134,6 +152,7 @@
     public Drawable icon;
     public ThumbnailData thumbnail;
     @ViewDebug.ExportedProperty(category="recents")
+    @Deprecated
     public String title;
     @ViewDebug.ExportedProperty(category="recents")
     public String titleDescription;
@@ -142,6 +161,7 @@
     @ViewDebug.ExportedProperty(category="recents")
     public int colorBackground;
     @ViewDebug.ExportedProperty(category="recents")
+    @Deprecated
     public boolean useLightOnPrimaryColor;
 
     /**
@@ -153,10 +173,13 @@
      * The state isLaunchTarget will be set for the correct task upon launching Recents.
      */
     @ViewDebug.ExportedProperty(category="recents")
+    @Deprecated
     public boolean isLaunchTarget;
     @ViewDebug.ExportedProperty(category="recents")
+    @Deprecated
     public boolean isStackTask;
     @ViewDebug.ExportedProperty(category="recents")
+    @Deprecated
     public boolean isSystemApp;
     @ViewDebug.ExportedProperty(category="recents")
     public boolean isDockable;
@@ -165,6 +188,7 @@
      * Resize mode. See {@link ActivityInfo#resizeMode}.
      */
     @ViewDebug.ExportedProperty(category="recents")
+    @Deprecated
     public int resizeMode;
 
     @ViewDebug.ExportedProperty(category="recents")
@@ -173,12 +197,31 @@
     @ViewDebug.ExportedProperty(category="recents")
     public boolean isLocked;
 
+    @Deprecated
     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
     public Task() {
         // Do nothing
     }
 
+    public Task(TaskKey key) {
+        this.key = key;
+        this.taskDescription = new TaskDescription();
+    }
+
+    public Task(TaskKey key, int colorPrimary, int colorBackground,
+            boolean isDockable, boolean isLocked, TaskDescription taskDescription,
+            ComponentName topActivity) {
+        this.key = key;
+        this.colorPrimary = colorPrimary;
+        this.colorBackground = colorBackground;
+        this.taskDescription = taskDescription;
+        this.isDockable = isDockable;
+        this.isLocked = isLocked;
+        this.topActivity = topActivity;
+    }
+
+    @Deprecated
     public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title,
             String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget,
             boolean isStackTask, boolean isSystemApp, boolean isDockable,
@@ -206,6 +249,7 @@
     /**
      * Copies the metadata from another task, but retains the current callbacks.
      */
+    @Deprecated
     public void copyFrom(Task o) {
         this.key = o.key;
         this.icon = o.icon;
@@ -228,6 +272,7 @@
     /**
      * Add a callback.
      */
+    @Deprecated
     public void addCallback(TaskCallbacks cb) {
         if (!mCallbacks.contains(cb)) {
             mCallbacks.add(cb);
@@ -237,11 +282,13 @@
     /**
      * Remove a callback.
      */
+    @Deprecated
     public void removeCallback(TaskCallbacks cb) {
         mCallbacks.remove(cb);
     }
 
     /** Updates the task's windowing mode. */
+    @Deprecated
     public void setWindowingMode(int windowingMode) {
         key.setWindowingMode(windowingMode);
         int callbackCount = mCallbacks.size();
@@ -251,6 +298,7 @@
     }
 
     /** Notifies the callback listeners that this task has been loaded */
+    @Deprecated
     public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
         this.icon = applicationIcon;
         this.thumbnail = thumbnailData;
@@ -261,6 +309,7 @@
     }
 
     /** Notifies the callback listeners that this task has been unloaded */
+    @Deprecated
     public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
         icon = defaultApplicationIcon;
         thumbnail = null;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
index 5f3dcd1..d378189 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
@@ -21,6 +21,7 @@
 /**
  * An interface for a task filter to query whether a particular task should show in a stack.
  */
+@Deprecated
 public interface TaskFilter {
     /** Returns whether the filter accepts the specified task */
     boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
index 23582d4..342cb75 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
@@ -34,7 +34,7 @@
      * Gets a specific entry in the cache with the specified key, regardless of whether the cached
      * value is valid or not.
      */
-    final synchronized V get(TaskKey key) {
+    public final synchronized V get(TaskKey key) {
         return getCacheEntry(key.id);
     }
 
@@ -42,7 +42,7 @@
      * Returns the value only if the key is valid (has not been updated since the last time it was
      * in the cache)
      */
-    final synchronized V getAndInvalidateIfModified(TaskKey key) {
+    public final synchronized V getAndInvalidateIfModified(TaskKey key) {
         TaskKey lastKey = mKeys.get(key.id);
         if (lastKey != null) {
             if ((lastKey.windowingMode != key.windowingMode) ||
@@ -59,7 +59,7 @@
     }
 
     /** Puts an entry in the cache for a specific key. */
-    final synchronized void put(TaskKey key, V value) {
+    public final synchronized void put(TaskKey key, V value) {
         if (key == null || value == null) {
             Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
             return;
@@ -70,14 +70,14 @@
 
 
     /** Removes a cache entry for a specific key. */
-    final synchronized void remove(TaskKey key) {
+    public final synchronized void remove(TaskKey key) {
         // Remove the key after the cache value because we need it to make the callback
         removeCacheEntry(key.id);
         mKeys.remove(key.id);
     }
 
     /** Removes all the entries in the cache. */
-    final synchronized void evictAll() {
+    public final synchronized void evictAll() {
         evictAllCache();
         mKeys.clear();
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
index fbb6ace..6b9b9f5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
@@ -21,6 +21,7 @@
 /**
  * A Task load queue
  */
+@Deprecated
 class TaskResourceLoadQueue {
 
     private final ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<>();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
index c731ac9..fd92bca 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
@@ -33,6 +33,7 @@
 /**
  * The task stack contains a list of multiple tasks.
  */
+@Deprecated
 public class TaskStack {
 
     private static final String TAG = "TaskStack";
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
index 2de7f74..26f6b59 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
@@ -34,6 +34,7 @@
  * The generic set of animation properties to animate a {@link View}. The animation can have
  * different interpolators, start delays and durations for each of the different properties.
  */
+@Deprecated
 public class AnimationProps {
 
     private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
index 45728c4..30bea32 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
@@ -27,6 +27,7 @@
 /**
  * An outline provider that has a clip and outline that can be animated.
  */
+@Deprecated
 public class AnimateableViewBounds extends ViewOutlineProvider {
 
     private static final float MIN_ALPHA = 0.1f;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/KeyguardManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/KeyguardManagerCompat.java
new file mode 100644
index 0000000..c42e7e3
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/KeyguardManagerCompat.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.shared.system;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+
+public class KeyguardManagerCompat {
+    private final KeyguardManager mKeyguardManager;
+
+    public KeyguardManagerCompat(Context context) {
+        mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+    }
+
+    public boolean isDeviceLocked(int userId) {
+        return mKeyguardManager.isDeviceLocked(userId);
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
new file mode 100644
index 0000000..a529903
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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.shared.system;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+
+public class RecentTaskInfoCompat {
+
+    private ActivityManager.RecentTaskInfo mInfo;
+
+    public RecentTaskInfoCompat(ActivityManager.RecentTaskInfo info) {
+        mInfo = info;
+    }
+
+    public int getUserId() {
+        return mInfo.userId;
+    }
+
+    public boolean supportsSplitScreenMultiWindow() {
+        return mInfo.supportsSplitScreenMultiWindow;
+    }
+
+    public ComponentName getTopActivity() {
+        return mInfo.topActivity;
+    }
+
+    public ActivityManager.TaskDescription getTaskDescription() {
+        return mInfo.taskDescription;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
new file mode 100644
index 0000000..eaf8d9b
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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.shared.system;
+
+import android.app.ActivityManager;
+
+public class TaskDescriptionCompat {
+
+    private ActivityManager.TaskDescription mTaskDescription;
+
+    public TaskDescriptionCompat(ActivityManager.TaskDescription td) {
+        mTaskDescription = td;
+    }
+
+    public int getPrimaryColor() {
+        return mTaskDescription != null
+                ? mTaskDescription.getPrimaryColor()
+                : 0;
+    }
+
+    public int getBackgroundColor() {
+        return mTaskDescription != null
+                ? mTaskDescription.getBackgroundColor()
+                : 0;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java
index b2b140e..de2a3e4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java
@@ -17,7 +17,7 @@
 
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.view.DisplayListCanvas;
+import android.graphics.RecordingCanvas;
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.WindowCallbacks;
@@ -55,7 +55,7 @@
         }
 
         @Override
-        public void onPostDraw(DisplayListCanvas canvas) {
+        public void onPostDraw(RecordingCanvas canvas) {
             WindowCallbacksCompat.this.onPostDraw(canvas);
         }
     };
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 265a961..34df15f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -29,13 +29,13 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.settingslib.Utils;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 import java.io.File;
 
@@ -50,13 +50,6 @@
  */
 public class KeyguardHostView extends FrameLayout implements SecurityCallback {
 
-    public interface OnDismissAction {
-        /**
-         * @return true if the dismiss should be deferred
-         */
-        boolean onDismiss();
-    }
-
     private AudioManager mAudioManager;
     private TelephonyManager mTelephonyManager = null;
     protected ViewMediatorCallback mViewMediatorCallback;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 6d1313c..db78667 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -28,7 +28,6 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import androidx.core.graphics.ColorUtils;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.util.ArraySet;
@@ -41,6 +40,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import androidx.core.graphics.ColorUtils;
+
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.Dependency;
@@ -64,7 +65,6 @@
 
     private TextView mLogoutView;
     private KeyguardClockSwitch mClockView;
-    private View mClockSeparator;
     private TextView mOwnerInfo;
     private KeyguardSliceView mKeyguardSlice;
     private Runnable mPendingMarqueeStart;
@@ -75,8 +75,8 @@
     private boolean mWasPulsing;
     private float mDarkAmount = 0;
     private int mTextColor;
-    private float mWidgetPadding;
     private int mLastLayoutHeight;
+    private int mSmallClockPadding;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -175,14 +175,12 @@
         }
         mOwnerInfo = findViewById(R.id.owner_info);
         mKeyguardSlice = findViewById(R.id.keyguard_status_area);
-        mClockSeparator = findViewById(R.id.clock_separator);
         mVisibleInDoze = Sets.newArraySet(mClockView, mKeyguardSlice);
         mTextColor = mClockView.getCurrentTextColor();
 
         int clockStroke = getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke);
         mClockView.getPaint().setStrokeWidth(clockStroke);
         mClockView.addOnLayoutChangeListener(this);
-        mClockSeparator.addOnLayoutChangeListener(this);
         mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
         onSliceContentChanged();
 
@@ -199,26 +197,18 @@
     }
 
     /**
-     * Moves clock and separator, adjusting margins when slice content changes.
+     * Moves clock, adjusting margins when slice content changes.
      */
     private void onSliceContentChanged() {
         boolean smallClock = mKeyguardSlice.hasHeader() || mPulsing;
-        float clockScale = smallClock ? mSmallClockScale : 1;
-
         RelativeLayout.LayoutParams layoutParams =
                 (RelativeLayout.LayoutParams) mClockView.getLayoutParams();
-        int height = mClockView.getHeight();
-        layoutParams.bottomMargin = (int) -(height - (clockScale * height));
+        layoutParams.bottomMargin = smallClock ? mSmallClockPadding : 0;
         mClockView.setLayoutParams(layoutParams);
-
-        layoutParams = (RelativeLayout.LayoutParams) mClockSeparator.getLayoutParams();
-        layoutParams.topMargin = smallClock ? (int) mWidgetPadding : 0;
-        layoutParams.bottomMargin = layoutParams.topMargin;
-        mClockSeparator.setLayoutParams(layoutParams);
     }
 
     /**
-     * Animate clock and its separator when necessary.
+     * Animate clock when necessary.
      */
     @Override
     public void onLayoutChange(View view, int left, int top, int right, int bottom,
@@ -258,25 +248,6 @@
                 mClockView.setStyle(style);
                 mClockView.invalidate();
             }
-        } else if (view == mClockSeparator) {
-            boolean hasSeparator = hasHeader && !mPulsing;
-            float alpha = hasSeparator ? 1 : 0;
-            mClockSeparator.animate().cancel();
-            if (shouldAnimate) {
-                boolean isAwake = mDarkAmount != 0;
-                mClockSeparator.setY(oldTop + heightOffset);
-                mClockSeparator.animate()
-                        .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                        .setDuration(duration)
-                        .setListener(isAwake ? null : new KeepAwakeAnimationListener(getContext()))
-                        .setStartDelay(delay)
-                        .y(top)
-                        .alpha(alpha)
-                        .start();
-            } else {
-                mClockSeparator.setY(top);
-                mClockSeparator.setAlpha(alpha);
-            }
         }
     }
 
@@ -291,7 +262,8 @@
 
     @Override
     public void onDensityOrFontScaleChanged() {
-        mWidgetPadding = getResources().getDimension(R.dimen.widget_vertical_padding);
+        mSmallClockPadding = getResources()
+                .getDimensionPixelSize(R.dimen.widget_small_clock_padding);
         if (mClockView != null) {
             mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                     getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
@@ -352,6 +324,7 @@
             }
         }
         mOwnerInfo.setText(info);
+        updateDark();
     }
 
     @Override
@@ -434,7 +407,6 @@
         updateDozeVisibleViews();
         mKeyguardSlice.setDarkAmount(mDarkAmount);
         mClockView.setTextColor(blendedTextColor);
-        mClockSeparator.setBackgroundColor(blendedTextColor);
     }
 
     private void layoutOwnerInfo() {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 45f1686..08691ec 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -54,7 +54,7 @@
             if (mTextView != null && mTextView.isEnabled()) {
                 mTextView.append(Character.forDigit(mDigit, 10));
             }
-            userActivity();;
+            userActivity();
         }
     };
 
@@ -118,7 +118,7 @@
 
         a = context.obtainStyledAttributes(attrs, android.R.styleable.View);
         if (!a.hasValueOrEmpty(android.R.styleable.View_background)) {
-            setBackground(mContext.getDrawable(R.drawable.ripple_drawable));
+            setBackground(mContext.getDrawable(R.drawable.ripple_drawable_pin));
         }
         a.recycle();
         setContentDescription(mDigitText.getText().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index e58538d..e1b8dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -29,46 +29,69 @@
 
     @Override
     public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.startPendingIntentDismissingKeyguard(intent);
     }
 
     @Override
     public void startActivity(Intent intent, boolean dismissShade) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.startActivity(intent, dismissShade);
     }
 
     @Override
     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.startActivity(intent, onlyProvisioned, dismissShade);
     }
 
     @Override
     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.startActivity(intent, dismissShade, callback);
     }
 
     @Override
     public void postStartActivityDismissingKeyguard(Intent intent, int delay) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.postStartActivityDismissingKeyguard(intent, delay);
     }
 
     @Override
     public void postStartActivityDismissingKeyguard(PendingIntent intent) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.postStartActivityDismissingKeyguard(intent);
     }
 
     @Override
     public void postQSRunnableDismissingKeyguard(Runnable runnable) {
-        if (mActualStarter == null) return;
+        if (mActualStarter == null) {
+            return;
+        }
         mActualStarter.postQSRunnableDismissingKeyguard(runnable);
     }
 
+    @Override
+    public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancel,
+            boolean afterKeyguardGone) {
+        if (mActualStarter == null) {
+            return;
+        }
+        mActualStarter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone);
+    }
+
     public void setActivityStarterImpl(ActivityStarter starter) {
         mActualStarter = starter;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 2c821b2..494880e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -48,16 +48,22 @@
 import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.AppOpsListener;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -343,6 +349,14 @@
 
         mProviders.put(LockscreenGestureLogger.class, () -> new LockscreenGestureLogger());
 
+        mProviders.put(KeyguardEnvironment.class, () -> new KeyguardEnvironmentImpl());
+        mProviders.put(ShadeController.class, () ->
+                SysUiServiceProvider.getComponent(mContext, StatusBar.class));
+        mProviders.put(NotificationRemoteInputManager.Callback.class,
+                () -> new StatusBarRemoteInputCallback(mContext));
+
+        mProviders.put(InitController.class, InitController::new);
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
 
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 77f4bf5..d8eb965 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -30,7 +30,7 @@
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.DisplayListCanvas;
+import android.graphics.RecordingCanvas;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
@@ -381,7 +381,7 @@
                     try {
                         Bitmap wallpaper = mWallpaperManager.getBitmap(true /* hardware */);
                         if (wallpaper != null
-                                && wallpaper.getByteCount() > DisplayListCanvas.MAX_BITMAP_SIZE) {
+                                && wallpaper.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
                             throw new RuntimeException("Wallpaper is too large to draw!");
                         }
                         return wallpaper;
diff --git a/packages/SystemUI/src/com/android/systemui/InitController.java b/packages/SystemUI/src/com/android/systemui/InitController.java
new file mode 100644
index 0000000..52ba66a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/InitController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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;
+
+import java.util.ArrayList;
+
+/**
+ * Created by {@link Dependency} on SystemUI startup. Add tasks which need to be executed only
+ * after all other dependencies have been created.
+ */
+public class InitController {
+
+    private final ArrayList<Runnable> mTasks = new ArrayList<>();
+
+    /**
+     * Add a task to be executed after {@link Dependency#start()}
+     * @param runnable the task to be executed
+     */
+    public void addPostInitTask(Runnable runnable) {
+        mTasks.add(runnable);
+    }
+
+    /**
+     * Run post-init tasks and remove them from the tasks list
+     */
+    public void executePostInitTasks() {
+        while (!mTasks.isEmpty()) {
+            mTasks.remove(0).run();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 3007b6e..c844496 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -207,11 +207,11 @@
 
         mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mOverlay.setAlpha(0);
-        mOverlay.setAllowForceDark(false);
+        mOverlay.setForceDarkAllowed(false);
 
         mBottomOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mBottomOverlay.setAlpha(0);
-        mBottomOverlay.setAllowForceDark(false);
+        mBottomOverlay.setForceDarkAllowed(false);
 
         updateViews();
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 78053b2..92aa652 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -194,6 +194,7 @@
                 mServices[i].onBootCompleted();
             }
         }
+        Dependency.get(InitController.class).executePostInitTasks();
         log.traceEnd();
         Dependency.get(PluginManager.class).addPluginListener(
                 new PluginListener<OverlayPlugin>() {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 258b6f6..c4bf27b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -32,6 +32,7 @@
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -133,7 +134,7 @@
             Context context) {
         providers.put(StatusBarStateController.class, StatusBarStateController::new);
         providers.put(NotificationLockscreenUserManager.class,
-                () -> new NotificationLockscreenUserManager(context));
+                () -> new NotificationLockscreenUserManagerImpl(context));
         providers.put(VisualStabilityManager.class, VisualStabilityManager::new);
         providers.put(NotificationGroupManager.class, NotificationGroupManager::new);
         providers.put(NotificationMediaManager.class, () -> new NotificationMediaManager(context));
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 38a90cf..53cdee5 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -202,7 +202,8 @@
 
         // Close Recent Apps if needed
         SysUiServiceProvider.getComponent(mContext, CommandQueue.class).animateCollapsePanels(
-                CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
+                CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+                false /* force */);
 
         boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index 5739c99..96af08b 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -44,7 +44,7 @@
         // Because space is usually constrained in the auto use-case, there should not be a
         // pinned notification when the shade has been expanded. Ensure this by not pinning any
         // notification if the shade is already opened.
-        if (!mPresenter.isPresenterFullyCollapsed()) {
+        if (!getPresenter().isPresenterFullyCollapsed()) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/car/CarNotificationMediaManager.java
new file mode 100644
index 0000000..f34d6b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/car/CarNotificationMediaManager.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.car;
+
+import android.content.Context;
+
+import com.android.systemui.statusbar.NotificationMediaManager;
+
+public class CarNotificationMediaManager extends NotificationMediaManager {
+    public CarNotificationMediaManager(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+        // Do nothing, we don't want to display media art in the lock screen for a car.
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
index a015a18..e4b2e07 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
@@ -22,6 +22,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.Dependency.DependencyProvider;
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.car.CarFacetButtonController;
 import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
@@ -46,5 +47,7 @@
                 () -> new CarNotificationEntryManager(context));
         providers.put(CarFacetButtonController.class, () -> new CarFacetButtonController(context));
         providers.put(HvacController.class, () -> new HvacController(context));
+        providers.put(NotificationMediaManager.class,
+                () -> new CarNotificationMediaManager(context));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
index f217596..5bb5b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.recents.views;
 
-import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.graphics.Point;
@@ -25,14 +24,11 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
-import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.shared.recents.model.TaskStack;
 
 public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
     private static final String TAG = "TaskViewAccessibilityDelegate";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5c0b328..daaefb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
+
+import android.app.StatusBarManager;
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricPromptReceiver;
@@ -24,7 +27,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
+
 import androidx.annotation.VisibleForTesting;
 import android.util.Pair;
 
@@ -117,7 +120,7 @@
         default void removeIcon(String slot) { }
         default void disable(int state1, int state2, boolean animate) { }
         default void animateExpandNotificationsPanel() { }
-        default void animateCollapsePanels(int flags) { }
+        default void animateCollapsePanels(int flags, boolean force) { }
         default void togglePanel() { }
         default void animateExpandSettingsPanel(String obj) { }
         default void setSystemUiVisibility(int vis, int fullscreenStackVis,
@@ -169,7 +172,13 @@
     }
 
     @VisibleForTesting
-    protected CommandQueue() {
+    public CommandQueue() {
+    }
+
+    public boolean panelsEnabled() {
+        return (mDisable1 & StatusBarManager.DISABLE_EXPAND) == 0
+                && (mDisable2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
+                && !ONLY_CORE_APPS;
     }
 
     public void addCallbacks(Callbacks callbacks) {
@@ -234,10 +243,10 @@
         }
     }
 
-    public void animateCollapsePanels(int flags) {
+    public void animateCollapsePanels(int flags, boolean force) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_COLLAPSE_PANELS);
-            mHandler.obtainMessage(MSG_COLLAPSE_PANELS, flags, 0).sendToTarget();
+            mHandler.obtainMessage(MSG_COLLAPSE_PANELS, flags, force ? 1 : 0).sendToTarget();
         }
     }
 
@@ -592,7 +601,7 @@
                     break;
                 case MSG_COLLAPSE_PANELS:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).animateCollapsePanels(msg.arg1);
+                        mCallbacks.get(i).animateCollapsePanels(msg.arg1, msg.arg2 != 0);
                     }
                     break;
                 case MSG_TOGGLE_PANEL:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 18151d0..1f57634 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -29,9 +29,9 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
+import android.graphics.RecordingCanvas;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.DisplayListCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.view.ViewAnimationUtils;
@@ -192,8 +192,8 @@
                 // Our hardware drawing proparties can be null if the finishing started but we have
                 // never drawn before. In that case we are not doing a render thread animation
                 // anyway, so we need to use the normal drawing.
-                DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
-                displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius,
+                RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+                recordingCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius,
                         mHwCirclePaint);
             } else {
                 updateCircleColor();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index cfa09bc..f3a46ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -29,6 +29,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
 
 /**
@@ -41,11 +42,14 @@
     // Dependencies:
     private final NotificationRemoteInputManager mRemoteInputManager =
             Dependency.get(NotificationRemoteInputManager.class);
+    private final NotificationEntryManager mEntryManager =
+            Dependency.get(NotificationEntryManager.class);
+    private final NotificationGroupManager mGroupManager =
+            Dependency.get(NotificationGroupManager.class);
 
     private final Context mContext;
 
     protected NotificationPresenter mPresenter;
-    protected NotificationEntryManager mEntryManager;
 
     public NotificationListener(Context context) {
         mContext = context;
@@ -61,7 +65,7 @@
             return;
         }
         final RankingMap currentRanking = getCurrentRanking();
-        mPresenter.getHandler().post(() -> {
+        Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
             for (StatusBarNotification sbn : notifications) {
                 mEntryManager.addNotification(sbn, currentRanking);
             }
@@ -73,7 +77,7 @@
             final RankingMap rankingMap) {
         if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
         if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
-            mPresenter.getHandler().post(() -> {
+            Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
                 processForRemoteInput(sbn.getNotification(), mContext);
                 String key = sbn.getKey();
                 boolean isUpdate =
@@ -83,7 +87,7 @@
                 // anyway. This is true also when the summary is canceled,
                 // because children are automatically canceled by NoMan in that case.
                 if (!ENABLE_CHILD_NOTIFICATIONS
-                        && mPresenter.getGroupManager().isChildInGroupWithSummary(sbn)) {
+                        && mGroupManager.isChildInGroupWithSummary(sbn)) {
                     if (DEBUG) {
                         Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
                     }
@@ -112,7 +116,7 @@
         if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
         if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
             final String key = sbn.getKey();
-            mPresenter.getHandler().post(() -> {
+            Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
                 mEntryManager.removeNotification(key, rankingMap);
             });
         }
@@ -123,16 +127,14 @@
         if (DEBUG) Log.d(TAG, "onRankingUpdate");
         if (rankingMap != null) {
             RankingMap r = onPluginRankingUpdate(rankingMap);
-            mPresenter.getHandler().post(() -> {
+            Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
                 mEntryManager.updateNotificationRanking(r);
             });
         }
     }
 
-    public void setUpWithPresenter(NotificationPresenter presenter,
-            NotificationEntryManager entryManager) {
+    public void setUpWithPresenter(NotificationPresenter presenter) {
         mPresenter = presenter;
-        mEntryManager = entryManager;
 
         try {
             registerAsSystemService(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 89a842e..bc662e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -1,516 +1,61 @@
 /*
  * 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
+ * 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
+ * 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.app.ActivityManager;
-import android.app.KeyguardManager;
-import android.app.Notification;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
 import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
-import android.util.Log;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
-import com.android.systemui.Dumpable;
-import com.android.systemui.OverviewProxyService;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Handles keeping track of the current user, profiles, and various things related to hiding
- * contents, redacting notifications, and the lockscreen.
- */
-public class NotificationLockscreenUserManager implements Dumpable, StateListener {
-    private static final String TAG = "LockscreenUserManager";
-    private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
-    public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
-    public static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
+public interface NotificationLockscreenUserManager {
+    String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+    String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
             = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
 
-    private final DevicePolicyManager mDevicePolicyManager;
-    private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
-    private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
-    private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
-    private final DeviceProvisionedController mDeviceProvisionedController =
-            Dependency.get(DeviceProvisionedController.class);
-    private final UserManager mUserManager;
-    private final IStatusBarService mBarService;
-    private final LockPatternUtils mLockPatternUtils;
-    private final KeyguardManager mKeyguardManager;
-    private StatusBarKeyguardViewManager mKeyguardViewManager;
-
-    private boolean mShowLockscreenNotifications;
-    private boolean mAllowLockscreenRemoteInput;
-    private int mState = StatusBarState.SHADE;
-
-    protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-
-            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
-                    isCurrentProfile(getSendingUserId())) {
-                mUsersAllowingPrivateNotifications.clear();
-                updateLockscreenNotificationSetting();
-                mEntryManager.updateNotifications();
-            } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
-                if (userId != mCurrentUserId && isCurrentProfile(userId)) {
-                    updatePublicMode();
-                    mPresenter.onWorkChallengeChanged();
-                    mEntryManager.updateNotifications();
-                }
-            }
-        }
-    };
-
-    protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-                updateCurrentProfilesCache();
-                Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
-                updateLockscreenNotificationSetting();
-                updatePublicMode();
-                mPresenter.onUserSwitched(mCurrentUserId);
-                mEntryManager.getNotificationData().filterAndSort();
-            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
-                updateCurrentProfilesCache();
-            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
-                // Start the overview connection to the launcher service
-                Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
-            } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
-                final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
-                final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
-                if (intentSender != null) {
-                    try {
-                        mContext.startIntentSender(intentSender, null, 0, 0, 0);
-                    } catch (IntentSender.SendIntentException e) {
-                        /* ignore */
-                    }
-                }
-                if (notificationKey != null) {
-                    final int count =
-                            mEntryManager.getNotificationData().getActiveNotifications().size();
-                    final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
-                    final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
-                            rank, count, true);
-                    try {
-                        mBarService.onNotificationClick(notificationKey, nv);
-                    } catch (RemoteException e) {
-                        /* ignore */
-                    }
-                }
-            }
-        }
-    };
-
-    protected final Context mContext;
-    protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
-
-    protected int mCurrentUserId = 0;
-    protected NotificationPresenter mPresenter;
-    protected NotificationEntryManager mEntryManager;
-    protected ContentObserver mLockscreenSettingsObserver;
-    protected ContentObserver mSettingsObserver;
-
-    public NotificationLockscreenUserManager(Context context) {
-        mContext = context;
-        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mCurrentUserId = ActivityManager.getCurrentUser();
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mLockPatternUtils = new LockPatternUtils(mContext);
-        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        Dependency.get(StatusBarStateController.class).addListener(this);
-    }
-
-    public void setUpWithPresenter(NotificationPresenter presenter,
-            NotificationEntryManager entryManager) {
-        mPresenter = presenter;
-        mEntryManager = entryManager;
-
-        mLockscreenSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
-            @Override
-            public void onChange(boolean selfChange) {
-                // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
-                // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
-                mUsersAllowingPrivateNotifications.clear();
-                mUsersAllowingNotifications.clear();
-                // ... and refresh all the notifications
-                updateLockscreenNotificationSetting();
-                mEntryManager.updateNotifications();
-            }
-        };
-
-        mSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
-            @Override
-            public void onChange(boolean selfChange) {
-                updateLockscreenNotificationSetting();
-                if (mDeviceProvisionedController.isDeviceProvisioned()) {
-                    mEntryManager.updateNotifications();
-                }
-            }
-        };
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
-                mLockscreenSettingsObserver,
-                UserHandle.USER_ALL);
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
-                true,
-                mLockscreenSettingsObserver,
-                UserHandle.USER_ALL);
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
-                mSettingsObserver);
-
-        if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
-                    false,
-                    mSettingsObserver,
-                    UserHandle.USER_ALL);
-        }
-
-        IntentFilter allUsersFilter = new IntentFilter();
-        allUsersFilter.addAction(
-                DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-        allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
-        mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
-                null, null);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_USER_ADDED);
-        filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiver(mBaseBroadcastReceiver, filter);
-
-        IntentFilter internalFilter = new IntentFilter();
-        internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
-        mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
-
-        updateCurrentProfilesCache();
-
-        mSettingsObserver.onChange(false);  // set up
-    }
-
-    public boolean shouldShowLockscreenNotifications() {
-        return mShowLockscreenNotifications;
-    }
-
-    public boolean shouldAllowLockscreenRemoteInput() {
-        return mAllowLockscreenRemoteInput;
-    }
-
-    public boolean isCurrentProfile(int userId) {
-        synchronized (mCurrentProfiles) {
-            return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
-        }
-    }
-
-    public void setKeyguardViewManager(StatusBarKeyguardViewManager sbkvm) {
-        mKeyguardViewManager = sbkvm;
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        mState = newState;
-        updatePublicMode();
-    }
-
-    public void updatePublicMode() {
-        //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
-        // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
-        // asking if the keyguard is showing. We still need to check it though because showing the
-        // camera on the keyguard has a state of SHADE but the keyguard is still showing.
-        boolean showingKeyguard = mState != StatusBarState.SHADE
-                || mKeyguardViewManager.isShowing();
-        boolean devicePublic = showingKeyguard && mKeyguardViewManager.isSecure(getCurrentUserId());
-
-        SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
-        for (int i = currentProfiles.size() - 1; i >= 0; i--) {
-            final int userId = currentProfiles.valueAt(i).id;
-            boolean isProfilePublic = devicePublic;
-            if (!devicePublic && userId != mCurrentUserId) {
-                // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
-                // due to a race condition where this code could be called before
-                // TrustManagerService updates its internal records, resulting in an incorrect
-                // state being cached in mLockscreenPublicMode. (b/35951989)
-                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
-                        && mKeyguardViewManager.isSecure(userId)) {
-                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
-                }
-            }
-            setLockscreenPublicMode(isProfilePublic, userId);
-        }
-    }
+    boolean shouldAllowLockscreenRemoteInput();
 
     /**
-     * Returns true if notifications are temporarily disabled for this user for security reasons,
-     * regardless of the normal settings for that user.
+     * @param userId user Id
+     * @return true if we re on a secure lock screen
      */
-    private boolean shouldTemporarilyHideNotifications(int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            userId = mCurrentUserId;
-        }
-        return KeyguardUpdateMonitor.getInstance(mContext).isUserInLockdown(userId);
-    }
+    boolean isLockscreenPublicMode(int userId);
 
-    /**
-     * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
-     * If so, notifications should be hidden.
-     */
-    public boolean shouldHideNotifications(int userId) {
-        return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
-                || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
-                || shouldTemporarilyHideNotifications(userId);
-    }
+    void setUpWithPresenter(NotificationPresenter presenter);
 
-    /**
-     * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
-     * package-specific override.
-     */
-    public boolean shouldHideNotifications(String key) {
-        if (mEntryManager == null) {
-            Log.wtf(TAG, "mEntryManager was null!", new Throwable());
-            return true;
-        }
-        return isLockscreenPublicMode(mCurrentUserId)
-                && mEntryManager.getNotificationData().getVisibilityOverride(key) ==
-                        Notification.VISIBILITY_SECRET;
-    }
+    int getCurrentUserId();
 
-    public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
-        if (mEntryManager == null) {
-            Log.wtf(TAG, "mEntryManager was null!", new Throwable());
-            return false;
-        }
-        return mShowLockscreenNotifications
-                && !mEntryManager.getNotificationData().isAmbient(sbn.getKey());
-    }
+    boolean isCurrentProfile(int userId);
 
-    private void setShowLockscreenNotifications(boolean show) {
-        mShowLockscreenNotifications = show;
-    }
+    void destroy();
 
-    private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
-        mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
-    }
+    SparseArray<UserInfo> getCurrentProfiles();
 
-    protected void updateLockscreenNotificationSetting() {
-        final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
-                1,
-                mCurrentUserId) != 0;
-        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
-                null /* admin */, mCurrentUserId);
-        final boolean allowedByDpm = (dpmFlags
-                & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+    void setLockscreenPublicMode(boolean isProfilePublic, int userId);
 
-        setShowLockscreenNotifications(show && allowedByDpm);
+    boolean shouldShowLockscreenNotifications();
 
-        if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
-            final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
-                    0,
-                    mCurrentUserId) != 0;
-            final boolean remoteInputDpm =
-                    (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+    boolean shouldHideNotifications(int userId);
+    boolean shouldHideNotifications(String key);
+    boolean shouldShowOnKeyguard(StatusBarNotification sbn);
 
-            setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
-        } else {
-            setLockscreenAllowRemoteInput(false);
-        }
-    }
+    boolean isAnyProfilePublicMode();
 
-    /**
-     * Has the given user chosen to allow their private (full) notifications to be shown even
-     * when the lockscreen is in "public" (secure & locked) mode?
-     */
-    public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
-        if (userHandle == UserHandle.USER_ALL) {
-            return true;
-        }
+    void updatePublicMode();
 
-        if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
-            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
-                    mContext.getContentResolver(),
-                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
-            final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
-                    DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
-            final boolean allowed = allowedByUser && allowedByDpm;
-            mUsersAllowingPrivateNotifications.append(userHandle, allowed);
-            return allowed;
-        }
+    boolean needsRedaction(Entry entry);
 
-        return mUsersAllowingPrivateNotifications.get(userHandle);
-    }
-
-    private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
-        if (userHandle == UserHandle.USER_ALL) {
-            return true;
-        }
-        final int dpmFlags =
-                mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
-        return (dpmFlags & feature) == 0;
-    }
-
-    /**
-     * Save the current "public" (locked and secure) state of the lockscreen.
-     */
-    public void setLockscreenPublicMode(boolean publicMode, int userId) {
-        mLockscreenPublicMode.put(userId, publicMode);
-    }
-
-    public boolean isLockscreenPublicMode(int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            return mLockscreenPublicMode.get(mCurrentUserId, false);
-        }
-        return mLockscreenPublicMode.get(userId, false);
-    }
-
-    /**
-     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
-     * "public" (secure & locked) mode?
-     */
-    private boolean userAllowsNotificationsInPublic(int userHandle) {
-        if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
-            return true;
-        }
-
-        if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
-            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
-                    mContext.getContentResolver(),
-                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
-            final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
-                    DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
-            final boolean allowed = allowedByUser && allowedByDpm;
-            mUsersAllowingNotifications.append(userHandle, allowed);
-            return allowed;
-        }
-
-        return mUsersAllowingNotifications.get(userHandle);
-    }
-
-    /** @return true if the entry needs redaction when on the lockscreen. */
-    public boolean needsRedaction(NotificationData.Entry ent) {
-        int userId = ent.notification.getUserId();
-
-        boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
-        boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
-        boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
-
-        boolean notificationRequestsRedaction =
-                ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
-        boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
-
-        return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
-    }
-
-    private boolean packageHasVisibilityOverride(String key) {
-        if (mEntryManager == null) {
-            Log.wtf(TAG, "mEntryManager was null!", new Throwable());
-            return true;
-        }
-        return mEntryManager.getNotificationData().getVisibilityOverride(key) ==
-                Notification.VISIBILITY_PRIVATE;
-    }
-
-    private void updateCurrentProfilesCache() {
-        synchronized (mCurrentProfiles) {
-            mCurrentProfiles.clear();
-            if (mUserManager != null) {
-                for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
-                    mCurrentProfiles.put(user.id, user);
-                }
-            }
-        }
-    }
-
-    public boolean isAnyProfilePublicMode() {
-        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
-            if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the current user id. This can change if the user is switched.
-     */
-    public int getCurrentUserId() {
-        return mCurrentUserId;
-    }
-
-    public SparseArray<UserInfo> getCurrentProfiles() {
-        return mCurrentProfiles;
-    }
-
-    public void destroy() {
-        mContext.unregisterReceiver(mBaseBroadcastReceiver);
-        mContext.unregisterReceiver(mAllUsersReceiver);
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("NotificationLockscreenUserManager state:");
-        pw.print("  mCurrentUserId=");
-        pw.println(mCurrentUserId);
-        pw.print("  mShowLockscreenNotifications=");
-        pw.println(mShowLockscreenNotifications);
-        pw.print("  mAllowLockscreenRemoteInput=");
-        pw.println(mAllowLockscreenRemoteInput);
-        pw.print("  mCurrentProfiles=");
-        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
-            final int userId = mCurrentProfiles.valueAt(i).id;
-            pw.print("" + userId + " ");
-        }
-        pw.println();
-    }
+    boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
new file mode 100644
index 0000000..178c5c5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2018 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 static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.app.Notification;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
+import com.android.systemui.OverviewProxyService;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Handles keeping track of the current user, profiles, and various things related to hiding
+ * contents, redacting notifications, and the lockscreen.
+ */
+public class NotificationLockscreenUserManagerImpl implements
+        Dumpable, NotificationLockscreenUserManager, StateListener {
+    private static final String TAG = "LockscreenUserManager";
+    private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
+
+    private final DeviceProvisionedController mDeviceProvisionedController =
+            Dependency.get(DeviceProvisionedController.class);
+    private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+
+    // Lazy
+    private NotificationEntryManager mEntryManager;
+
+    private final DevicePolicyManager mDevicePolicyManager;
+    private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
+    private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+    private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
+    private final UserManager mUserManager;
+    private final IStatusBarService mBarService;
+
+    private boolean mShowLockscreenNotifications;
+    private boolean mAllowLockscreenRemoteInput;
+    private LockPatternUtils mLockPatternUtils;
+    protected KeyguardManager mKeyguardManager;
+    private int mState = StatusBarState.SHADE;
+
+    protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+
+            if (ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
+                    isCurrentProfile(getSendingUserId())) {
+                mUsersAllowingPrivateNotifications.clear();
+                updateLockscreenNotificationSetting();
+                getEntryManager().updateNotifications();
+            }
+        }
+    };
+
+    protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                updateCurrentProfilesCache();
+                Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+                updateLockscreenNotificationSetting();
+                updatePublicMode();
+                mPresenter.onUserSwitched(mCurrentUserId);
+                getEntryManager().getNotificationData().filterAndSort();
+            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+                updateCurrentProfilesCache();
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                // Start the overview connection to the launcher service
+                Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+            } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
+                final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+                final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+                if (intentSender != null) {
+                    try {
+                        mContext.startIntentSender(intentSender, null, 0, 0, 0);
+                    } catch (IntentSender.SendIntentException e) {
+                        /* ignore */
+                    }
+                }
+                if (notificationKey != null) {
+                    final int count =
+                            getEntryManager().getNotificationData().getActiveNotifications().size();
+                    final int rank = getEntryManager().getNotificationData().getRank(notificationKey);
+                    final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
+                            rank, count, true);
+                    try {
+                        mBarService.onNotificationClick(notificationKey, nv);
+                    } catch (RemoteException e) {
+                        /* ignore */
+                    }
+                }
+            }
+        }
+    };
+
+    protected final Context mContext;
+    protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
+
+    protected int mCurrentUserId = 0;
+    protected NotificationPresenter mPresenter;
+    protected ContentObserver mLockscreenSettingsObserver;
+    protected ContentObserver mSettingsObserver;
+
+    private NotificationEntryManager getEntryManager() {
+        if (mEntryManager == null) {
+            mEntryManager = Dependency.get(NotificationEntryManager.class);
+        }
+        return mEntryManager;
+    }
+
+    public NotificationLockscreenUserManagerImpl(Context context) {
+        mContext = context;
+        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mCurrentUserId = ActivityManager.getCurrentUser();
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        Dependency.get(StatusBarStateController.class).addListener(this);
+        mLockPatternUtils = new LockPatternUtils(context);
+        mKeyguardManager = context.getSystemService(KeyguardManager.class);
+    }
+
+    public void setUpWithPresenter(NotificationPresenter presenter) {
+        mPresenter = presenter;
+
+        mLockscreenSettingsObserver = new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
+            @Override
+            public void onChange(boolean selfChange) {
+                // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
+                // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
+                mUsersAllowingPrivateNotifications.clear();
+                mUsersAllowingNotifications.clear();
+                // ... and refresh all the notifications
+                updateLockscreenNotificationSetting();
+                getEntryManager().updateNotifications();
+            }
+        };
+
+        mSettingsObserver = new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
+            @Override
+            public void onChange(boolean selfChange) {
+                updateLockscreenNotificationSetting();
+                if (mDeviceProvisionedController.isDeviceProvisioned()) {
+                    getEntryManager().updateNotifications();
+                }
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
+                mLockscreenSettingsObserver,
+                UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+                true,
+                mLockscreenSettingsObserver,
+                UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
+                mSettingsObserver);
+
+        if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
+                    false,
+                    mSettingsObserver,
+                    UserHandle.USER_ALL);
+        }
+
+        mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL,
+                new IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                null, null);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        filter.addAction(Intent.ACTION_USER_ADDED);
+        filter.addAction(Intent.ACTION_USER_UNLOCKED);
+        mContext.registerReceiver(mBaseBroadcastReceiver, filter);
+
+        IntentFilter internalFilter = new IntentFilter();
+        internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+        mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+
+        updateCurrentProfilesCache();
+
+        mSettingsObserver.onChange(false);  // set up
+    }
+
+    public boolean shouldShowLockscreenNotifications() {
+        return mShowLockscreenNotifications;
+    }
+
+    public boolean shouldAllowLockscreenRemoteInput() {
+        return mAllowLockscreenRemoteInput;
+    }
+
+    public boolean isCurrentProfile(int userId) {
+        synchronized (mCurrentProfiles) {
+            return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
+        }
+    }
+
+    /**
+     * Returns true if notifications are temporarily disabled for this user for security reasons,
+     * regardless of the normal settings for that user.
+     */
+    private boolean shouldTemporarilyHideNotifications(int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            userId = mCurrentUserId;
+        }
+        return KeyguardUpdateMonitor.getInstance(mContext).isUserInLockdown(userId);
+    }
+
+    /**
+     * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+     * If so, notifications should be hidden.
+     */
+    public boolean shouldHideNotifications(int userId) {
+        return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
+                || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
+                || shouldTemporarilyHideNotifications(userId);
+    }
+
+    /**
+     * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+     * package-specific override.
+     */
+    public boolean shouldHideNotifications(String key) {
+        if (getEntryManager() == null) {
+            Log.wtf(TAG, "mEntryManager was null!", new Throwable());
+            return true;
+        }
+        return isLockscreenPublicMode(mCurrentUserId)
+                && getEntryManager().getNotificationData().getVisibilityOverride(key) ==
+                        Notification.VISIBILITY_SECRET;
+    }
+
+    public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+        if (getEntryManager() == null) {
+            Log.wtf(TAG, "mEntryManager was null!", new Throwable());
+            return false;
+        }
+        return mShowLockscreenNotifications
+                && !getEntryManager().getNotificationData().isAmbient(sbn.getKey());
+    }
+
+    private void setShowLockscreenNotifications(boolean show) {
+        mShowLockscreenNotifications = show;
+    }
+
+    private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
+        mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
+    }
+
+    protected void updateLockscreenNotificationSetting() {
+        final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                1,
+                mCurrentUserId) != 0;
+        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
+                null /* admin */, mCurrentUserId);
+        final boolean allowedByDpm = (dpmFlags
+                & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+        setShowLockscreenNotifications(show && allowedByDpm);
+
+        if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+            final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+                    0,
+                    mCurrentUserId) != 0;
+            final boolean remoteInputDpm =
+                    (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+
+            setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
+        } else {
+            setLockscreenAllowRemoteInput(false);
+        }
+    }
+
+    /**
+     * Has the given user chosen to allow their private (full) notifications to be shown even
+     * when the lockscreen is in "public" (secure & locked) mode?
+     */
+    public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+
+        if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
+            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
+            final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
+                    DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+            final boolean allowed = allowedByUser && allowedByDpm;
+            mUsersAllowingPrivateNotifications.append(userHandle, allowed);
+            return allowed;
+        }
+
+        return mUsersAllowingPrivateNotifications.get(userHandle);
+    }
+
+    private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+        final int dpmFlags =
+                mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
+        return (dpmFlags & feature) == 0;
+    }
+
+    /**
+     * Save the current "public" (locked and secure) state of the lockscreen.
+     */
+    public void setLockscreenPublicMode(boolean publicMode, int userId) {
+        mLockscreenPublicMode.put(userId, publicMode);
+    }
+
+    public boolean isLockscreenPublicMode(int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            return mLockscreenPublicMode.get(mCurrentUserId, false);
+        }
+        return mLockscreenPublicMode.get(userId, false);
+    }
+
+    /**
+     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+     * "public" (secure & locked) mode?
+     */
+    private boolean userAllowsNotificationsInPublic(int userHandle) {
+        if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
+            return true;
+        }
+
+        if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+            final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
+                    DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+            final boolean allowed = allowedByUser && allowedByDpm;
+            mUsersAllowingNotifications.append(userHandle, allowed);
+            return allowed;
+        }
+
+        return mUsersAllowingNotifications.get(userHandle);
+    }
+
+    /** @return true if the entry needs redaction when on the lockscreen. */
+    public boolean needsRedaction(NotificationData.Entry ent) {
+        int userId = ent.notification.getUserId();
+
+        boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
+        boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
+        boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
+
+        boolean notificationRequestsRedaction =
+                ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+        boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
+
+        return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
+    }
+
+    private boolean packageHasVisibilityOverride(String key) {
+        if (getEntryManager() == null) {
+            Log.wtf(TAG, "mEntryManager was null!", new Throwable());
+            return true;
+        }
+        return getEntryManager().getNotificationData().getVisibilityOverride(key) ==
+                Notification.VISIBILITY_PRIVATE;
+    }
+
+    private void updateCurrentProfilesCache() {
+        synchronized (mCurrentProfiles) {
+            mCurrentProfiles.clear();
+            if (mUserManager != null) {
+                for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
+                    mCurrentProfiles.put(user.id, user);
+                }
+            }
+        }
+    }
+
+    public boolean isAnyProfilePublicMode() {
+        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+            if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the current user id. This can change if the user is switched.
+     */
+    public int getCurrentUserId() {
+        return mCurrentUserId;
+    }
+
+    public SparseArray<UserInfo> getCurrentProfiles() {
+        return mCurrentProfiles;
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+        mState = newState;
+        updatePublicMode();
+    }
+
+    public void updatePublicMode() {
+        //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
+        // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
+        // asking if the keyguard is showing. We still need to check it though because showing the
+        // camera on the keyguard has a state of SHADE but the keyguard is still showing.
+        final boolean showingKeyguard = mState != StatusBarState.SHADE
+              || mKeyguardMonitor.isShowing();
+        final boolean devicePublic = showingKeyguard && isSecure(getCurrentUserId());
+
+
+        // Look for public mode users. Users are considered public in either case of:
+        //   - device keyguard is shown in secure mode;
+        //   - profile is locked with a work challenge.
+        SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
+        for (int i = currentProfiles.size() - 1; i >= 0; i--) {
+            final int userId = currentProfiles.valueAt(i).id;
+            boolean isProfilePublic = devicePublic;
+            if (!devicePublic && userId != getCurrentUserId()) {
+                // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
+                // due to a race condition where this code could be called before
+                // TrustManagerService updates its internal records, resulting in an incorrect
+                // state being cached in mLockscreenPublicMode. (b/35951989)
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+                        && isSecure(userId)) {
+                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
+                }
+            }
+            setLockscreenPublicMode(isProfilePublic, userId);
+        }
+    }
+
+
+//    public void updatePublicMode() {
+//        //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
+//        // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
+//        // asking if the keyguard is showing. We still need to check it though because showing the
+//        // camera on the keyguard has a state of SHADE but the keyguard is still showing.
+//        final boolean showingKeyguard = mState != StatusBarState.SHADE
+//              || mKeyguardMonitor.isShowing();
+//        final boolean devicePublic = showingKeyguard && isSecure(getCurrentUserId());
+//
+//
+//        // Look for public mode users. Users are considered public in either case of:
+//        //   - device keyguard is shown in secure mode;
+//        //   - profile is locked with a work challenge.
+//        SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
+//        for (int i = currentProfiles.size() - 1; i >= 0; i--) {
+//            final int userId = currentProfiles.valueAt(i).id;
+//            boolean isProfilePublic = devicePublic;
+//            if (!devicePublic && userId != getCurrentUserId()) {
+//                // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
+//                // due to a race condition where this code could be called before
+//                // TrustManagerService updates its internal records, resulting in an incorrect
+//                // state being cached in mLockscreenPublicMode. (b/35951989)
+//                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+//                        && isSecure(userId)) {
+//                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
+//                }
+//            }
+//            setLockscreenPublicMode(isProfilePublic, userId);
+//        }
+//    }
+
+    private boolean isSecure(int userId) {
+        return mKeyguardMonitor.isSecure() || mLockPatternUtils.isSecure(userId);
+    }
+
+    public void destroy() {
+        mContext.unregisterReceiver(mBaseBroadcastReceiver);
+        mContext.unregisterReceiver(mAllUsersReceiver);
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("NotificationLockscreenUserManager state:");
+        pw.print("  mCurrentUserId=");
+        pw.println(mCurrentUserId);
+        pw.print("  mShowLockscreenNotifications=");
+        pw.println(mShowLockscreenNotifications);
+        pw.print("  mAllowLockscreenRemoteInput=");
+        pw.println(mAllowLockscreenRemoteInput);
+        pw.print("  mCurrentProfiles=");
+        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+            final int userId = mCurrentProfiles.valueAt(i).id;
+            pw.print("" + userId + " ");
+        }
+        pw.println();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 2db9945..c437b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -15,19 +15,46 @@
  */
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.Dependency.MAIN_HANDLER;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
+import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
+import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
+
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
+import com.android.systemui.Interpolators;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.LockscreenWallpaper;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ScrimState;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -42,15 +69,45 @@
     private static final String TAG = "NotificationMediaManager";
     public static final boolean DEBUG_MEDIA = false;
 
+    private final StatusBarStateController mStatusBarStateController
+            = Dependency.get(StatusBarStateController.class);
+    private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+    private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+
+    // Late binding
+    private NotificationEntryManager mEntryManager;
+
+    // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
+    @Nullable
+    private ShadeController mShadeController;
+    @Nullable
+    private StatusBarWindowController mStatusBarWindowController;
+
+    @Nullable
+    private BiometricUnlockController mBiometricUnlockController;
+    @Nullable
+    private ScrimController mScrimController;
+    @Nullable
+    private LockscreenWallpaper mLockscreenWallpaper;
+
+    protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+    protected final PorterDuffXfermode mSrcOverXferMode =
+            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
+
+    private final Handler mHandler = Dependency.get(MAIN_HANDLER);
+
     private final Context mContext;
     private final MediaSessionManager mMediaSessionManager;
 
     protected NotificationPresenter mPresenter;
-    protected NotificationEntryManager mEntryManager;
     private MediaController mMediaController;
     private String mMediaNotificationKey;
     private MediaMetadata mMediaMetadata;
 
+    private BackDropView mBackdrop;
+    private ImageView mBackdropFront;
+    private ImageView mBackdropBack;
+
     private final MediaController.Callback mMediaListener = new MediaController.Callback() {
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
@@ -77,6 +134,29 @@
         }
     };
 
+    @Nullable
+    private ShadeController getShadeController() {
+        if (mShadeController == null) {
+            mShadeController = Dependency.get(ShadeController.class);
+        }
+        return mShadeController;
+    }
+
+    @Nullable
+    private StatusBarWindowController getWindowController() {
+        if (mStatusBarWindowController == null) {
+            mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+        }
+        return mStatusBarWindowController;
+    }
+
+    private NotificationEntryManager getEntryManager() {
+        if (mEntryManager == null) {
+            mEntryManager = Dependency.get(NotificationEntryManager.class);
+        }
+        return mEntryManager;
+    }
+
     public NotificationMediaManager(Context context) {
         mContext = context;
         mMediaSessionManager
@@ -85,10 +165,8 @@
         // in session state
     }
 
-    public void setUpWithPresenter(NotificationPresenter presenter,
-            NotificationEntryManager entryManager) {
+    public void setUpWithPresenter(NotificationPresenter presenter) {
         mPresenter = presenter;
-        mEntryManager = entryManager;
     }
 
     public void onNotificationRemoved(String key) {
@@ -109,8 +187,9 @@
     public void findAndUpdateMediaNotifications() {
         boolean metaDataChanged = false;
 
-        synchronized (mEntryManager.getNotificationData()) {
-            ArrayList<NotificationData.Entry> activeNotifications = mEntryManager
+        NotificationEntryManager manager = getEntryManager();
+        synchronized (manager.getNotificationData()) {
+            ArrayList<NotificationData.Entry> activeNotifications = manager
                     .getNotificationData().getActiveNotifications();
             final int N = activeNotifications.size();
 
@@ -199,7 +278,7 @@
         }
 
         if (metaDataChanged) {
-            mEntryManager.updateNotifications();
+            getEntryManager().updateNotifications();
         }
         mPresenter.updateMediaMetaData(metaDataChanged, true);
     }
@@ -272,4 +351,204 @@
         }
         mMediaController = null;
     }
+
+    /**
+     * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
+     */
+    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+        Trace.beginSection("StatusBar#updateMediaMetaData");
+        if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
+            Trace.endSection();
+            return;
+        }
+
+        if (mBackdrop == null) {
+            Trace.endSection();
+            return; // called too early
+        }
+
+        boolean wakeAndUnlock = mBiometricUnlockController != null
+            && mBiometricUnlockController.isWakeAndUnlock();
+        if (mKeyguardMonitor.isLaunchTransitionFadingAway() || wakeAndUnlock) {
+            mBackdrop.setVisibility(View.INVISIBLE);
+            Trace.endSection();
+            return;
+        }
+
+        MediaMetadata mediaMetadata = getMediaMetadata();
+
+        if (DEBUG_MEDIA) {
+            Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
+                    + getMediaNotificationKey()
+                    + " metadata=" + mediaMetadata
+                    + " metaDataChanged=" + metaDataChanged
+                    + " state=" + mStatusBarStateController.getState());
+        }
+
+        Drawable artworkDrawable = null;
+        if (mediaMetadata != null) {
+            Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+            if (artworkBitmap == null) {
+                artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+                // might still be null
+            }
+            if (artworkBitmap != null) {
+                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
+            }
+        }
+        boolean allowWhenShade = false;
+        if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
+            Bitmap lockWallpaper =
+                    mLockscreenWallpaper != null ? mLockscreenWallpaper.getBitmap() : null;
+            if (lockWallpaper != null) {
+                artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
+                        mBackdropBack.getResources(), lockWallpaper);
+                // We're in the SHADE mode on the SIM screen - yet we still need to show
+                // the lockscreen wallpaper in that mode.
+                allowWhenShade = mStatusBarStateController.getState() == KEYGUARD;
+            }
+        }
+
+        boolean hideBecauseOccluded = getShadeController() != null
+                && getShadeController().isOccluded();
+
+        final boolean hasArtwork = artworkDrawable != null;
+        mColorExtractor.setHasBackdrop(hasArtwork);
+        if (mScrimController != null) {
+            mScrimController.setHasBackdrop(hasArtwork);
+        }
+
+        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
+                && (mStatusBarStateController.getState() != StatusBarState.SHADE || allowWhenShade)
+                &&  mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+                        != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+                && !hideBecauseOccluded) {
+            // time to show some art!
+            if (mBackdrop.getVisibility() != View.VISIBLE) {
+                mBackdrop.setVisibility(View.VISIBLE);
+                if (allowEnterAnimation) {
+                    mBackdrop.setAlpha(0);
+                    mBackdrop.animate().alpha(1f);
+                } else {
+                    mBackdrop.animate().cancel();
+                    mBackdrop.setAlpha(1f);
+                }
+                if (getWindowController() != null) {
+                    getWindowController().setBackdropShowing(true);
+                }
+                metaDataChanged = true;
+                if (DEBUG_MEDIA) {
+                    Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
+                }
+            }
+            if (metaDataChanged) {
+                if (mBackdropBack.getDrawable() != null) {
+                    Drawable drawable =
+                            mBackdropBack.getDrawable().getConstantState()
+                                    .newDrawable(mBackdropFront.getResources()).mutate();
+                    mBackdropFront.setImageDrawable(drawable);
+                    mBackdropFront.setAlpha(1f);
+                    mBackdropFront.setVisibility(View.VISIBLE);
+                } else {
+                    mBackdropFront.setVisibility(View.INVISIBLE);
+                }
+
+                if (DEBUG_MEDIA_FAKE_ARTWORK) {
+                    final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
+                    Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
+                    mBackdropBack.setBackgroundColor(0xFFFFFFFF);
+                    mBackdropBack.setImageDrawable(new ColorDrawable(c));
+                } else {
+                    mBackdropBack.setImageDrawable(artworkDrawable);
+                }
+
+                if (mBackdropFront.getVisibility() == View.VISIBLE) {
+                    if (DEBUG_MEDIA) {
+                        Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
+                                + mBackdropFront.getDrawable()
+                                + " to "
+                                + mBackdropBack.getDrawable());
+                    }
+                    mBackdropFront.animate()
+                            .setDuration(250)
+                            .alpha(0f).withEndAction(mHideBackdropFront);
+                }
+            }
+        } else {
+            // need to hide the album art, either because we are unlocked, on AOD
+            // or because the metadata isn't there to support it
+            if (mBackdrop.getVisibility() != View.GONE) {
+                if (DEBUG_MEDIA) {
+                    Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
+                }
+                boolean cannotAnimateDoze = getShadeController() != null
+                        && getShadeController().isDozing()
+                        && !ScrimState.AOD.getAnimateChange();
+                if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+                        == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+                        || hideBecauseOccluded || cannotAnimateDoze) {
+
+                    // We are unlocking directly - no animation!
+                    mBackdrop.setVisibility(View.GONE);
+                    mBackdropBack.setImageDrawable(null);
+                    if (getWindowController() != null) {
+                        getWindowController().setBackdropShowing(false);
+                    }
+                } else {
+                    if (getWindowController() != null) {
+                        getWindowController().setBackdropShowing(false);
+                    }
+                    mBackdrop.animate()
+                            .alpha(0)
+                            .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
+                            .setDuration(300)
+                            .setStartDelay(0)
+                            .withEndAction(() -> {
+                                mBackdrop.setVisibility(View.GONE);
+                                mBackdropFront.animate().cancel();
+                                mBackdropBack.setImageDrawable(null);
+                                mHandler.post(mHideBackdropFront);
+                            });
+                    if (mKeyguardMonitor.isKeyguardFadingAway()) {
+                        mBackdrop.animate()
+                                // Make it disappear faster, as the focus should be on the activity
+                                // behind.
+                                .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                                .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
+                                .setInterpolator(Interpolators.LINEAR)
+                                .start();
+                    }
+                }
+            }
+        }
+        Trace.endSection();
+    }
+
+    public void setup(BackDropView backdrop, ImageView backdropFront, ImageView backdropBack,
+            ScrimController scrimController, LockscreenWallpaper lockscreenWallpaper) {
+        mBackdrop = backdrop;
+        mBackdropFront = backdropFront;
+        mBackdropBack = backdropBack;
+        mScrimController = scrimController;
+        mLockscreenWallpaper = lockscreenWallpaper;
+    }
+
+    public void setBiometricUnlockController(BiometricUnlockController biometricUnlockController) {
+        mBiometricUnlockController = biometricUnlockController;
+    }
+
+    /**
+     * Hide the album artwork that is fading out and release its bitmap.
+     */
+    protected final Runnable mHideBackdropFront = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG_MEDIA) {
+                Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
+            }
+            mBackdropFront.setVisibility(View.INVISIBLE);
+            mBackdropFront.animate().cancel();
+            mBackdropFront.setImageDrawable(null);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index c58eb80..5c8f4cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.view.View;
 
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -31,9 +32,7 @@
  * for affecting the state of the system (e.g. starting an intent, given that the presenter may
  * want to perform some action before doing so).
  */
-public interface NotificationPresenter extends NotificationData.Environment,
-        NotificationRemoteInputManager.Callback,
-        ExpandableNotificationRow.OnExpandClickListener,
+public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener,
         ActivatableNotificationView.OnActivatedListener,
         NotificationEntryManager.Callback {
     /**
@@ -43,59 +42,23 @@
     boolean isPresenterFullyCollapsed();
 
     /**
-     * Returns true if the presenter is locked. For example, if the keyguard is active.
-     */
-    boolean isPresenterLocked();
-
-    /**
      * Runs the given intent. The presenter may want to run some animations or close itself when
      * this happens.
      */
     void startNotificationGutsIntent(Intent intent, int appUid, ExpandableNotificationRow row);
 
     /**
-     * Returns the Handler for NotificationPresenter.
-     */
-    Handler getHandler();
-
-    /**
      * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
      */
     void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation);
 
     /**
-     * Called when the locked status of the device is changed for a work profile.
-     */
-    void onWorkChallengeChanged();
-
-    /**
      * Called when the current user changes.
      * @param newUserId new user id
      */
     void onUserSwitched(int newUserId);
 
     /**
-     * Gets the NotificationLockscreenUserManager for this Presenter.
-     */
-    NotificationLockscreenUserManager getNotificationLockscreenUserManager();
-
-    /**
-     * Wakes the device up if dozing.
-     *
-     * @param time the time when the request to wake up was issued
-     * @param where which view caused this wake up request
-     */
-    void wakeUpIfDozing(long time, View where);
-
-    /**
-     * True if the device currently requires a PIN, pattern, or password to unlock.
-     *
-     * @param userId user id to query about
-     * @return true iff the device is locked
-     */
-    boolean isDeviceLocked(int userId);
-
-    /**
      * @return true iff the device is in vr mode
      */
     boolean isDeviceInVrMode();
@@ -114,7 +77,36 @@
     int getMaxNotificationsWhileLocked(boolean recompute);
 
     /**
-     * Called when the row states are updated by NotificationViewHierarchyManager.
+     * True if the presenter
+     * @return
+     */
+    default boolean isPresenterLocked() { return false; }
+
+    /**
+     * Called when the row states are updated by {@link NotificationViewHierarchyManager}.
      */
     void onUpdateRowStates();
+
+    /**
+     * @return true if the shade is collapsing.
+     */
+    boolean isCollapsing();
+
+    /**
+     * @return true if the shade is collapsing to show an activity over the lock screen
+     */
+    default public boolean isCollapsingToShowActivityOverLockscreen() {
+        return false;
+    }
+
+    /**
+     * Get the {@link ActivityLaunchAnimator} from the presenter so it can be queried by
+     * {@link com.android.systemui.statusbar.phone.StatusBar}
+     * @return the current animator
+     * @deprecated This is only here for now because StatusBar is still the ActivityLaunchAnimator
+     * callback but shouldn't be.
+     */
+    default public ActivityLaunchAnimator getActivityLaunchAnimator() {
+        return null;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index ea7e03e..f30377e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -46,9 +47,11 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
+import com.android.systemui.InitController;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
 import java.io.FileDescriptor;
@@ -97,13 +100,18 @@
             Dependency.get(NotificationLockscreenUserManager.class);
     protected final SmartReplyController mSmartReplyController =
             Dependency.get(SmartReplyController.class);
+    private final NotificationEntryManager mEntryManager
+            = Dependency.get(NotificationEntryManager.class);
+
+    // Lazy
+    private ShadeController mShadeController;
 
     protected final Context mContext;
     private final UserManager mUserManager;
+    private final KeyguardManager mKeyguardManager;
 
     protected RemoteInputController mRemoteInputController;
     protected NotificationPresenter mPresenter;
-    protected NotificationEntryManager mEntryManager;
     protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
             mNotificationLifetimeFinishedCallback;
     protected IStatusBarService mBarService;
@@ -115,7 +123,7 @@
         @Override
         public boolean onClickHandler(
                 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
-            mPresenter.wakeUpIfDozing(SystemClock.uptimeMillis(), view);
+            getShadeController().wakeUpIfDozing(SystemClock.uptimeMillis(), view);
 
             if (handleRemoteInput(view, pendingIntent)) {
                 return true;
@@ -240,7 +248,7 @@
                     return true;
                 }
                 if (mUserManager.getUserInfo(userId).isManagedProfile()
-                        && mPresenter.isDeviceLocked(userId)) {
+                        && mKeyguardManager.isDeviceLocked(userId)) {
                     mCallback.onLockedWorkRemoteInput(userId, row, view);
                     return true;
                 }
@@ -291,20 +299,26 @@
         }
     };
 
+    private ShadeController getShadeController() {
+        if (mShadeController == null) {
+            mShadeController = Dependency.get(ShadeController.class);
+        }
+        return mShadeController;
+    }
+
     public NotificationRemoteInputManager(Context context) {
         mContext = context;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         addLifetimeExtenders();
+        mKeyguardManager = context.getSystemService(KeyguardManager.class);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
-            NotificationEntryManager entryManager,
             Callback callback,
             RemoteInputController.Delegate delegate) {
         mPresenter = presenter;
-        mEntryManager = entryManager;
         mCallback = callback;
         mRemoteInputController = new RemoteInputController(delegate);
         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@@ -318,7 +332,7 @@
                     // view it is already canceled, so we'll need to cancel it on the apps behalf
                     // after sending - unless the app posts an update in the mean time, so wait a
                     // bit.
-                    mPresenter.getHandler().postDelayed(() -> {
+                    Dependency.get(Dependency.MAIN_HANDLER).postDelayed(() -> {
                         if (mEntriesKeptForRemoteInputActive.remove(entry)) {
                             mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 1495abf..cd3da123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -34,6 +34,7 @@
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -103,7 +104,8 @@
     }
 
     @Override
-    protected void onFinishInflate() {
+    @VisibleForTesting
+    public void onFinishInflate() {
         super.onFinishInflate();
         mShelfIcons = findViewById(R.id.content);
         mShelfIcons.setClipChildren(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 5b3082b..92765bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -24,6 +24,7 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -31,6 +32,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -57,6 +59,13 @@
             Dependency.get(NotificationGroupManager.class);
     protected final VisualStabilityManager mVisualStabilityManager =
             Dependency.get(VisualStabilityManager.class);
+    private final StatusBarStateController mStatusBarStateController =
+            Dependency.get(StatusBarStateController.class);
+    private final NotificationEntryManager mEntryManager =
+            Dependency.get(NotificationEntryManager.class);
+
+    // Lazy
+    private ShadeController mShadeController;
 
     /**
      * {@code true} if notifications not part of a group should by default be rendered in their
@@ -66,9 +75,15 @@
     private final boolean mAlwaysExpandNonGroupedNotification;
 
     private NotificationPresenter mPresenter;
-    private NotificationEntryManager mEntryManager;
     private NotificationListContainer mListContainer;
 
+    private ShadeController getShadeController() {
+        if (mShadeController == null) {
+            mShadeController = Dependency.get(ShadeController.class);
+        }
+        return mShadeController;
+    }
+
     public NotificationViewHierarchyManager(Context context) {
         Resources res = context.getResources();
         mAlwaysExpandNonGroupedNotification =
@@ -76,9 +91,8 @@
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
-            NotificationEntryManager entryManager, NotificationListContainer listContainer) {
+            NotificationListContainer listContainer) {
         mPresenter = presenter;
-        mEntryManager = entryManager;
         mListContainer = listContainer;
     }
 
@@ -291,9 +305,9 @@
         final int N = mListContainer.getContainerChildCount();
 
         int visibleNotifications = 0;
-        boolean isLocked = mPresenter.isPresenterLocked();
+        boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
         int maxNotifications = -1;
-        if (isLocked) {
+        if (onKeyguard) {
             maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
         }
         mListContainer.setMaxDisplayedNotifications(maxNotifications);
@@ -311,9 +325,9 @@
             boolean isChildNotification =
                     mGroupManager.isChildInGroupWithSummary(entry.notification);
 
-            row.setOnKeyguard(isLocked);
+            row.setOnKeyguard(onKeyguard);
 
-            if (!isLocked) {
+            if (!onKeyguard) {
                 // If mAlwaysExpandNonGroupedNotification is false, then only expand the
                 // very first notification and if it's not a child of grouped notifications.
                 row.setSystemExpanded(mAlwaysExpandNonGroupedNotification
@@ -321,7 +335,7 @@
                         && !row.isLowPriority()));
             }
 
-            entry.row.setOnAmbient(mPresenter.isDozing());
+            entry.row.setOnAmbient(getShadeController().isDozing());
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.row.isRemoved();
@@ -340,7 +354,7 @@
             }
             if (suppressedSummary
                     || mLockscreenUserManager.shouldHideNotifications(userId)
-                    || (isLocked && !showOnKeyguard)) {
+                    || (onKeyguard && !showOnKeyguard)) {
                 entry.row.setVisibility(View.GONE);
             } else {
                 boolean wasGone = entry.row.getVisibility() == View.GONE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index cc5fbe5..1e04377 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -38,7 +38,6 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import androidx.core.graphics.ColorUtils;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
@@ -49,6 +48,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.Interpolator;
 
+import androidx.core.graphics.ColorUtils;
+
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Interpolators;
@@ -121,6 +122,7 @@
     private StatusBarNotification mNotification;
     private final boolean mBlocked;
     private int mDensity;
+    private boolean mNightMode;
     private float mIconScale = 1.0f;
     private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private float mDotRadius;
@@ -171,10 +173,10 @@
         setNotification(sbn);
         setScaleType(ScaleType.CENTER);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
-        if (mNotification != null) {
-            setDecorColor(getContext().getColor(
-                    com.android.internal.R.color.notification_default_color_light));
-        }
+        Configuration configuration = context.getResources().getConfiguration();
+        mNightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        initializeDecorColor();
         reloadDimens();
         maybeUpdateIconScaleDimens();
     }
@@ -222,6 +224,12 @@
             maybeUpdateIconScaleDimens();
             updateDrawable();
         }
+        boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        if (nightMode != mNightMode) {
+            mNightMode = nightMode;
+            initializeDecorColor();
+        }
     }
 
     private void reloadDimens() {
@@ -540,6 +548,14 @@
         updateDecorColor();
     }
 
+    private void initializeDecorColor() {
+        if (mNotification != null) {
+            setDecorColor(getContext().getColor(mNightMode
+                    ? com.android.internal.R.color.notification_default_color_dark
+                    : com.android.internal.R.color.notification_default_color_light));
+        }
+    }
+
     private void updateDecorColor() {
         int color = NotificationUtils.interpolateColors(mDecorColor, Color.WHITE, mDarkAmount);
         if (mDotPaint.getColor() != color) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 78a5817..12c0fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -44,6 +44,7 @@
     private int mState;
     private int mLastState;
     private boolean mLeaveOpenOnKeyguardHide;
+    private boolean mKeyguardRequested;
 
     // TODO: b/115739177 (remove this explicit ordering if we can)
     @Retention(SOURCE)
@@ -173,6 +174,14 @@
         }
     }
 
+    public void setKeyguardRequested(boolean keyguardRequested) {
+        mKeyguardRequested = keyguardRequested;
+    }
+
+    public boolean isKeyguardRequested() {
+        return mKeyguardRequested;
+    }
+
     public static String describe(int state) {
         return StatusBarState.toShortString(state);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 24665ea..8799341 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -525,12 +525,6 @@
     }
 
     @Override
-    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
-        // Do nothing, we don't want to display media art in the lock screen for a car.
-    }
-
-
-    @Override
     public void animateExpandNotificationsPanel() {
         // Because space is usually constrained in the auto use-case, there should not be a
         // pinned notification when the shade has been expanded. Ensure this by removing all heads-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java
index 8cae806..9e99fbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java
@@ -33,10 +33,11 @@
     // Dependencies:
     private final ForegroundServiceController mFsc =
             Dependency.get(ForegroundServiceController.class);
+    private final NotificationEntryManager mEntryManager =
+            Dependency.get(NotificationEntryManager.class);
 
     private final Context mContext;
     protected NotificationPresenter mPresenter;
-    protected NotificationEntryManager mEntryManager;
     protected final AppOpsManager mAppOps;
 
     protected static final int[] OPS = new int[] {AppOpsManager.OP_CAMERA,
@@ -48,10 +49,8 @@
         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
     }
 
-    public void setUpWithPresenter(NotificationPresenter presenter,
-            NotificationEntryManager entryManager) {
+    public void setUpWithPresenter(NotificationPresenter presenter) {
         mPresenter = presenter;
-        mEntryManager = entryManager;
         mAppOps.startWatchingActive(OPS, this);
     }
 
@@ -62,7 +61,7 @@
     @Override
     public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
         mFsc.onAppOpChanged(code, uid, packageName, active);
-        mPresenter.getHandler().post(() -> {
+        Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
           mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index fbf12ed..3539fff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -51,21 +51,22 @@
 import android.view.View;
 import android.widget.ImageView;
 
-import androidx.annotation.Nullable;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
 import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -74,16 +75,23 @@
 import java.util.List;
 import java.util.Objects;
 
+import androidx.annotation.Nullable;
+
 /**
  * The list of currently displaying notifications.
  */
 public class NotificationData {
 
-    private final Environment mEnvironment;
-    private HeadsUpManager mHeadsUpManager;
+    /**
+     * These dependencies are late init-ed
+     */
+    private KeyguardEnvironment mEnvironment;
+    private ShadeController mShadeController;
+    private NotificationMediaManager mMediaManager;
+    private ForegroundServiceController mFsc;
+    private NotificationLockscreenUserManager mUserManager;
 
-    final ZenModeController mZen = Dependency.get(ZenModeController.class);
-    final ForegroundServiceController mFsc = Dependency.get(ForegroundServiceController.class);
+    private HeadsUpManager mHeadsUpManager;
 
     public static final class Entry {
         private static final long LAUNCH_COOLDOWN = 2000;
@@ -375,7 +383,8 @@
     private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
     private final ArrayList<Entry> mFilteredForUser = new ArrayList<>();
 
-    private NotificationGroupManager mGroupManager;
+    private final NotificationGroupManager mGroupManager
+            = Dependency.get(NotificationGroupManager.class);
 
     private RankingMap mRankingMap;
     private final Ranking mTmpRanking = new Ranking();
@@ -407,7 +416,7 @@
                 bRank = mRankingB.getRank();
             }
 
-            String mediaNotification = mEnvironment.getCurrentMediaNotificationKey();
+            String mediaNotification = getMediaManager().getMediaNotificationKey();
 
             // IMPORTANCE_MIN media streams are allowed to drift to the bottom
             final boolean aMedia = a.key.equals(mediaNotification)
@@ -442,13 +451,43 @@
         }
     };
 
-    public NotificationData(Environment environment) {
-        mEnvironment = environment;
-        mGroupManager = environment.getGroupManager();
+    private KeyguardEnvironment getEnvironment() {
+        if (mEnvironment == null) {
+            mEnvironment = Dependency.get(KeyguardEnvironment.class);
+        }
+        return mEnvironment;
+    }
+
+    private ShadeController getShadeController() {
+        if (mShadeController == null) {
+            mShadeController = Dependency.get(ShadeController.class);
+        }
+        return mShadeController;
+    }
+
+    private NotificationMediaManager getMediaManager() {
+        if (mMediaManager == null) {
+            mMediaManager = Dependency.get(NotificationMediaManager.class);
+        }
+        return mMediaManager;
+    }
+
+    private ForegroundServiceController getFsc() {
+        if (mFsc == null) {
+            mFsc = Dependency.get(ForegroundServiceController.class);
+        }
+        return mFsc;
+    }
+
+    private NotificationLockscreenUserManager getUserManager() {
+        if (mUserManager == null) {
+            mUserManager = Dependency.get(NotificationLockscreenUserManager.class);
+        }
+        return mUserManager;
     }
 
     /**
-     * Returns the sorted list of active notifications (depending on {@link Environment}
+     * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
      *
      * <p>
      * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
@@ -468,7 +507,7 @@
             for (int i = 0; i < N; i++) {
                 Entry entry = mEntries.valueAt(i);
                 final StatusBarNotification sbn = entry.notification;
-                if (!mEnvironment.isNotificationForCurrentProfiles(sbn)) {
+                if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
                     continue;
                 }
                 mFilteredForUser.add(entry);
@@ -719,27 +758,27 @@
      */
     public boolean shouldFilterOut(Entry entry) {
         final StatusBarNotification sbn = entry.notification;
-        if (!(mEnvironment.isDeviceProvisioned() ||
+        if (!(getEnvironment().isDeviceProvisioned() ||
                 showNotificationEvenIfUnprovisioned(sbn))) {
             return true;
         }
 
-        if (!mEnvironment.isNotificationForCurrentProfiles(sbn)) {
+        if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
             return true;
         }
 
-        if (mEnvironment.isSecurelyLocked(sbn.getUserId()) &&
+        if (getUserManager().isLockscreenPublicMode(sbn.getUserId()) &&
                 (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
-                        || mEnvironment.shouldHideNotifications(sbn.getUserId())
-                        || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
+                        || getUserManager().shouldHideNotifications(sbn.getUserId())
+                        || getUserManager().shouldHideNotifications(sbn.getKey()))) {
             return true;
         }
 
-        if (mEnvironment.isDozing() && shouldSuppressAmbient(entry)) {
+        if (getShadeController().isDozing() && shouldSuppressAmbient(entry)) {
             return true;
         }
 
-        if (!mEnvironment.isDozing() && shouldSuppressNotificationList(entry)) {
+        if (!getShadeController().isDozing() && shouldSuppressNotificationList(entry)) {
             return true;
         }
 
@@ -752,15 +791,16 @@
             return true;
         }
 
-        if (mFsc.isDungeonNotification(sbn) && !mFsc.isDungeonNeededForUser(sbn.getUserId())) {
+        if (getFsc().isDungeonNotification(sbn)
+                && !getFsc().isDungeonNeededForUser(sbn.getUserId())) {
             // this is a foreground-service disclosure for a user that does not need to show one
             return true;
         }
-        if (mFsc.isSystemAlertNotification(sbn)) {
+        if (getFsc().isSystemAlertNotification(sbn)) {
             final String[] apps = sbn.getNotification().extras.getStringArray(
                     Notification.EXTRA_FOREGROUND_APPS);
             if (apps != null && apps.length >= 1) {
-                if (!mFsc.isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
+                if (!getFsc().isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
                     return true;
                 }
             }
@@ -838,18 +878,8 @@
     /**
      * Provides access to keyguard state and user settings dependent data.
      */
-    public interface Environment {
-        public boolean isSecurelyLocked(int userId);
-        public boolean shouldHideNotifications(int userid);
-        public boolean shouldHideNotifications(String key);
-        public boolean isDeviceProvisioned();
-        public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
-        public String getCurrentMediaNotificationKey();
-        public NotificationGroupManager getGroupManager();
-
-        /**
-         * @return true iff the device is dozing
-         */
-        boolean isDozing();
+    public interface KeyguardEnvironment {
+        boolean isDeviceProvisioned();
+        boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 28d339a..3bea7db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -16,12 +16,9 @@
 package com.android.systemui.statusbar.notification;
 
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
-import static com.android.systemui.statusbar.NotificationRemoteInputManager
-        .FORCE_REMOTE_INPUT_HISTORY;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater
-        .FLAG_CONTENT_VIEW_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater
-        .FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 
 import android.annotation.Nullable;
 import android.app.Notification;
@@ -62,11 +59,12 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -74,13 +72,15 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.NotificationUpdateHandler;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -110,33 +110,31 @@
     protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
     protected final NotificationClicker mNotificationClicker = new NotificationClicker();
 
-    // Dependencies:
-    protected final NotificationLockscreenUserManager mLockscreenUserManager =
-            Dependency.get(NotificationLockscreenUserManager.class);
-    protected final NotificationGroupManager mGroupManager =
+    private final NotificationGroupManager mGroupManager =
             Dependency.get(NotificationGroupManager.class);
-    protected final NotificationGutsManager mGutsManager =
+    private final NotificationGutsManager mGutsManager =
             Dependency.get(NotificationGutsManager.class);
-    protected final NotificationRemoteInputManager mRemoteInputManager =
-            Dependency.get(NotificationRemoteInputManager.class);
-    protected final NotificationMediaManager mMediaManager =
-            Dependency.get(NotificationMediaManager.class);
-    protected final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-    protected final DeviceProvisionedController mDeviceProvisionedController =
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+    private final DeviceProvisionedController mDeviceProvisionedController =
             Dependency.get(DeviceProvisionedController.class);
-    protected final VisualStabilityManager mVisualStabilityManager =
+    private final VisualStabilityManager mVisualStabilityManager =
             Dependency.get(VisualStabilityManager.class);
-    protected final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
-    protected final ForegroundServiceController mForegroundServiceController =
+    private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+    private final ForegroundServiceController mForegroundServiceController =
             Dependency.get(ForegroundServiceController.class);
-    protected final NotificationListener mNotificationListener =
-            Dependency.get(NotificationListener.class);
-    protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+    private final AmbientPulseManager mAmbientPulseManager =
+            Dependency.get(AmbientPulseManager.class);
+
+    // Lazily retrieved dependencies
+    private NotificationRemoteInputManager mRemoteInputManager;
+    private NotificationMediaManager mMediaManager;
+    private NotificationListener mNotificationListener;
+    private ShadeController mShadeController;
 
     protected IDreamManager mDreamManager;
     protected IStatusBarService mBarService;
-    protected NotificationPresenter mPresenter;
-    protected Callback mCallback;
+    private NotificationPresenter mPresenter;
+    private Callback mCallback;
     protected PowerManager mPowerManager;
     protected NotificationListenerService.RankingMap mLatestRankingMap;
     protected HeadsUpManager mHeadsUpManager;
@@ -149,7 +147,6 @@
             = new ArrayList<>();
     private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
 
-
     private final class NotificationClicker implements View.OnClickListener {
 
         @Override
@@ -159,7 +156,7 @@
                 return;
             }
 
-            mPresenter.wakeUpIfDozing(SystemClock.uptimeMillis(), v);
+            getShadeController().wakeUpIfDozing(SystemClock.uptimeMillis(), v);
 
             final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
             final StatusBarNotification sbn = row.getStatusBarNotification();
@@ -232,20 +229,55 @@
         mDreamManager = IDreamManager.Stub.asInterface(
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mMessagingUtil = new NotificationMessagingUtil(context);
+        mNotificationData = new NotificationData();
+        Dependency.get(InitController.class).addPostInitTask(this::onPostInit);
+    }
+
+    private void onPostInit() {
         mGroupManager.setPendingEntries(mPendingNotifications);
     }
 
+    /**
+     * Our dependencies can have cyclic references, so some need to be lazy
+     */
+    private NotificationRemoteInputManager getRemoteInputManager() {
+        if (mRemoteInputManager == null) {
+            mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
+        }
+        return mRemoteInputManager;
+    }
+
+    private NotificationMediaManager getMediaManager() {
+        if (mMediaManager == null) {
+            mMediaManager = Dependency.get(NotificationMediaManager.class);
+        }
+        return mMediaManager;
+    }
+
+    private NotificationListener getNotificationListener() {
+        if (mNotificationListener == null) {
+            mNotificationListener = Dependency.get(NotificationListener.class);
+        }
+        return mNotificationListener;
+    }
+
+    private ShadeController getShadeController() {
+        if (mShadeController == null) {
+            mShadeController = Dependency.get(ShadeController.class);
+        }
+        return mShadeController;
+    }
+
     public void setUpWithPresenter(NotificationPresenter presenter,
             NotificationListContainer listContainer, Callback callback,
             HeadsUpManager headsUpManager) {
         mPresenter = presenter;
         mCallback = callback;
-        mNotificationData = new NotificationData(presenter);
         mHeadsUpManager = headsUpManager;
         mNotificationData.setHeadsUpManager(mHeadsUpManager);
         mListContainer = listContainer;
 
-        mHeadsUpObserver = new ContentObserver(mPresenter.getHandler()) {
+        mHeadsUpObserver = new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
             @Override
             public void onChange(boolean selfChange) {
                 boolean wasUsing = mUseHeadsUp;
@@ -278,7 +310,7 @@
         mNotificationLifetimeExtenders.add(mHeadsUpManager);
         mNotificationLifetimeExtenders.add(mAmbientPulseManager);
         mNotificationLifetimeExtenders.add(mGutsManager);
-        mNotificationLifetimeExtenders.addAll(mRemoteInputManager.getLifetimeExtenders());
+        mNotificationLifetimeExtenders.addAll(getRemoteInputManager().getLifetimeExtenders());
 
         for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
             extender.setCallback(key -> removeNotification(key, mLatestRankingMap));
@@ -294,6 +326,14 @@
         return mNotificationData;
     }
 
+    protected Context getContext() {
+        return mContext;
+    }
+
+    protected NotificationPresenter getPresenter() {
+        return mPresenter;
+    }
+
     public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
         return mGutsManager::openGuts;
     }
@@ -348,7 +388,7 @@
         row.setInflationCallback(this);
         row.setLongPressListener(getNotificationLongClicker());
         mListContainer.bindRow(row);
-        mRemoteInputManager.bindRow(row);
+        getRemoteInputManager().bindRow(row);
 
         // Get the app name.
         // Note that Notification.Builder#bindHeaderAppName has similar logic
@@ -387,7 +427,7 @@
                 true);
         NotificationData.Entry entry = mNotificationData.get(n.getKey());
 
-        mRemoteInputManager.onPerformRemoveNotification(n, entry);
+        getRemoteInputManager().onPerformRemoveNotification(n, entry);
         final String pkg = n.getPackageName();
         final String tag = n.getTag();
         final int id = n.getId();
@@ -512,7 +552,7 @@
             // sending look longer than it takes.
             // Also we should not defer the removal if reordering isn't allowed since otherwise
             // some notifications can't disappear before the panel is closed.
-            boolean ignoreEarliestRemovalTime = mRemoteInputManager.getController().isSpinning(key)
+            boolean ignoreEarliestRemovalTime = getRemoteInputManager().getController().isSpinning(key)
                     && !FORCE_REMOTE_INPUT_HISTORY
                     || !mVisualStabilityManager.isReorderingAllowed();
             mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
@@ -547,7 +587,7 @@
             extender.setShouldManageLifetime(entry, false /* shouldManage */);
         }
 
-        mMediaManager.onNotificationRemoved(key);
+        getMediaManager().onNotificationRemoved(key);
         mForegroundServiceController.removeNotification(entry.notification);
 
         if (entry.row != null) {
@@ -602,8 +642,8 @@
                 boolean isForeground = (row.getStatusBarNotification().getNotification().flags
                         & Notification.FLAG_FOREGROUND_SERVICE) != 0;
                 boolean keepForReply =
-                        mRemoteInputManager.shouldKeepForRemoteInputHistory(childEntry)
-                        || mRemoteInputManager.shouldKeepForSmartReplyHistory(childEntry);
+                        getRemoteInputManager().shouldKeepForRemoteInputHistory(childEntry)
+                        || getRemoteInputManager().shouldKeepForSmartReplyHistory(childEntry);
                 if (isForeground || keepForReply) {
                     // the child is a foreground service notification which we can't remove or it's
                     // a child we're keeping around for reply!
@@ -633,7 +673,6 @@
 
     protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser,
             StatusBarNotification sbn, ExpandableNotificationRow row) {
-        row.setNeedsRedaction(mLockscreenUserManager.needsRedaction(entry));
         boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
         boolean isUpdate = mNotificationData.get(entry.key) != null;
         boolean wasLowPriority = row.isLowPriority();
@@ -668,6 +707,8 @@
 
         row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, shouldHeadsUp(entry));
         row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, shouldPulse(entry));
+        row.setNeedsRedaction(
+                Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
         row.inflateViews();
     }
 
@@ -818,7 +859,7 @@
                 mNotificationData.getImportance(key));
 
         boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
-        if (mPresenter.isDozing()) {
+        if (getShadeController().isDozing()) {
             updateAlertState(entry, shouldPulse(entry), alertAgain, mAmbientPulseManager);
         } else {
             updateAlertState(entry, shouldHeadsUp(entry), alertAgain, mHeadsUpManager);
@@ -833,7 +874,8 @@
 
         if (DEBUG) {
             // Is this for you?
-            boolean isForCurrentUser = mPresenter.isNotificationForCurrentProfiles(notification);
+            boolean isForCurrentUser = Dependency.get(KeyguardEnvironment.class)
+                    .isNotificationForCurrentProfiles(notification);
             Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
         }
 
@@ -917,7 +959,7 @@
     public boolean shouldHeadsUp(NotificationData.Entry entry) {
         StatusBarNotification sbn = entry.notification;
 
-        if (mPresenter.isDozing()) {
+        if (getShadeController().isDozing()) {
             if (DEBUG) {
                 Log.d(TAG, "No heads up: device is dozing: " + sbn.getKey());
             }
@@ -998,7 +1040,7 @@
     protected boolean shouldPulse(NotificationData.Entry entry) {
         StatusBarNotification sbn = entry.notification;
 
-        if (!mPresenter.isDozing()) {
+        if (!getShadeController().isDozing()) {
             if (DEBUG) {
                 Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
             }
@@ -1076,7 +1118,7 @@
 
     protected void setNotificationsShown(String[] keys) {
         try {
-            mNotificationListener.setNotificationsShown(keys);
+            getNotificationListener().setNotificationsShown(keys);
         } catch (RuntimeException e) {
             Log.d(TAG, "failed setNotificationsShown: ", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index e96e176..b5fbde1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -56,8 +56,9 @@
     private final NotificationListenerService mNotificationListener =
             Dependency.get(NotificationListener.class);
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+    protected NotificationEntryManager mEntryManager
+            = Dependency.get(NotificationEntryManager.class);
 
-    protected NotificationEntryManager mEntryManager;
     protected Handler mHandler = new Handler();
     protected IStatusBarService mBarService;
     private long mLastVisibilityReportUptimeMs;
@@ -147,9 +148,7 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
     }
 
-    public void setUpWithEntryManager(NotificationEntryManager entryManager,
-            NotificationListContainer listContainer) {
-        mEntryManager = entryManager;
+    public void setUpWithContainer(NotificationListContainer listContainer) {
         mListContainer = listContainer;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 8110c1c..22c37fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -18,11 +18,11 @@
 
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater
-        .FLAG_CONTENT_VIEW_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater
-        .FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;
 
 import android.animation.Animator;
@@ -45,8 +45,8 @@
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
-import android.os.SystemClock;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -79,32 +79,31 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.logging.NotificationCounters;
+import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.notification.stack.StackScrollState;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.BooleanSupplier;
@@ -214,6 +213,11 @@
      */
     private boolean mIsAmbientPulsing;
 
+    /**
+     * Whether or not the notification should be redacted on the lock screen, i.e has sensitive
+     * content which should be redacted on the lock screen.
+     */
+    private boolean mNeedsRedaction;
     private boolean mLastChronometerRunning = true;
     private ViewStub mChildrenContainerStub;
     private NotificationGroupManager mGroupManager;
@@ -480,6 +484,9 @@
                 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
                         freeViewRunnable);
                 break;
+            case FLAG_CONTENT_VIEW_PUBLIC:
+                getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
+                        freeViewRunnable);
             default:
                 break;
         }
@@ -557,6 +564,9 @@
         if (mIconAnimationRunning) {
             setIconAnimationRunning(true);
         }
+        if (mLastChronometerRunning) {
+            setChronometerRunning(true);
+        }
         if (mNotificationParent != null) {
             mNotificationParent.updateChildrenHeaderAppearance();
         }
@@ -615,7 +625,8 @@
     }
 
     private void updateLimitsForView(NotificationContentView layout) {
-        boolean customView = layout.getContractedChild().getId()
+        boolean customView = layout.getContractedChild() != null
+                && layout.getContractedChild().getId()
                 != com.android.internal.R.id.status_bar_latest_event_content;
         boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
         boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
@@ -1569,7 +1580,14 @@
     }
 
     public void setNeedsRedaction(boolean needsRedaction) {
-        mNotificationInflater.setRedactAmbient(needsRedaction);
+        if (mNeedsRedaction != needsRedaction) {
+            mNeedsRedaction = needsRedaction;
+            updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, needsRedaction /* shouldInflate */);
+            mNotificationInflater.updateNeedsRedaction(needsRedaction);
+            if (!needsRedaction) {
+                freeContentViewWhenSafe(FLAG_CONTENT_VIEW_PUBLIC);
+            }
+        }
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 7856451..11cf8e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -423,11 +424,24 @@
         return mAmbientSingleLineChild;
     }
 
-    public void setContractedChild(View child) {
+    /**
+     * Sets the contracted view. Child may be null to remove the content view.
+     *
+     * @param child contracted content view to set
+     */
+    public void setContractedChild(@Nullable View child) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
             removeView(mContractedChild);
         }
+        if (child == null) {
+            mContractedChild = null;
+            mContractedWrapper = null;
+            if (mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED) {
+                mTransformationStartVisibleType = UNDEFINED;
+            }
+            return;
+        }
         addView(child);
         mContractedChild = child;
         mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
@@ -450,7 +464,12 @@
         return null;
     }
 
-    public void setExpandedChild(View child) {
+    /**
+     * Sets the expanded view. Child may be null to remove the content view.
+     *
+     * @param child expanded content view to set
+     */
+    public void setExpandedChild(@Nullable View child) {
         if (mExpandedChild != null) {
             mPreviousExpandedRemoteInputIntent = null;
             if (mExpandedRemoteInput != null) {
@@ -483,7 +502,12 @@
                 mContainingNotification);
     }
 
-    public void setHeadsUpChild(View child) {
+    /**
+     * Sets the heads up view. Child may be null to remove the content view.
+     *
+     * @param child heads up content view to set
+     */
+    public void setHeadsUpChild(@Nullable View child) {
         if (mHeadsUpChild != null) {
             mPreviousHeadsUpRemoteInputIntent = null;
             if (mHeadsUpRemoteInput != null) {
@@ -516,7 +540,12 @@
                 mContainingNotification);
     }
 
-    public void setAmbientChild(View child) {
+    /**
+     * Sets the ambient view. Child may be null to remove the content view.
+     *
+     * @param child ambient content view to set
+     */
+    public void setAmbientChild(@Nullable View child) {
         if (mAmbientChild != null) {
             mAmbientChild.animate().cancel();
             removeView(mAmbientChild);
@@ -542,6 +571,13 @@
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
         updateVisibility();
+        if (visibility != VISIBLE) {
+            // View is no longer visible so all content views are inactive.
+            for (Runnable r : mOnContentViewInactiveListeners.values()) {
+                r.run();
+            }
+            mOnContentViewInactiveListeners.clear();
+        }
     }
 
     private void updateVisibility() {
@@ -589,6 +625,12 @@
         mContentHeight = Math.min(mUnrestrictedContentHeight, maxContentHeight);
         selectLayout(mAnimate /* animate */, false /* force */);
 
+        if (mContractedChild == null) {
+            // Contracted child may be null if this is the public content view and we don't need to
+            // show it.
+            return;
+        }
+
         int minHeightHint = getMinContentHeightHint();
 
         NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
@@ -739,7 +781,7 @@
     }
 
     public int getMaxHeight() {
-        if (mContainingNotification.isOnAmbient()) {
+        if (mContainingNotification.isOnAmbient() && getShowingAmbientView() != null) {
             return getShowingAmbientView().getHeight();
         } else if (mExpandedChild != null) {
             return getViewHeight(VISIBLE_TYPE_EXPANDED)
@@ -747,8 +789,10 @@
         } else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
             return getViewHeight(VISIBLE_TYPE_HEADSUP)
                     + getExtraRemoteInputHeight(mHeadsUpRemoteInput);
+        } else if (mContractedChild != null) {
+            return getViewHeight(VISIBLE_TYPE_CONTRACTED);
         }
-        return getViewHeight(VISIBLE_TYPE_CONTRACTED);
+        return mNotificationMaxHeight;
     }
 
     private int getViewHeight(int visibleType) {
@@ -766,10 +810,11 @@
     }
 
     public int getMinHeight(boolean likeGroupExpanded) {
-        if (mContainingNotification.isOnAmbient()) {
+        if (mContainingNotification.isOnAmbient() && getShowingAmbientView() != null) {
             return getShowingAmbientView().getHeight();
         } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
-            return getViewHeight(VISIBLE_TYPE_CONTRACTED);
+            return mContractedChild != null
+                    ? getViewHeight(VISIBLE_TYPE_CONTRACTED) : mMinContractedHeight;
         } else {
             return mSingleLineView.getHeight();
         }
@@ -1104,7 +1149,8 @@
                 return VISIBLE_TYPE_EXPANDED;
             }
         } else {
-            if (noExpandedChild || (viewHeight <= getViewHeight(VISIBLE_TYPE_CONTRACTED)
+            if (noExpandedChild || (mContractedChild != null
+                    && viewHeight <= getViewHeight(VISIBLE_TYPE_CONTRACTED)
                     && (!mIsChildInGroup || isGroupExpanded()
                             || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
                 return VISIBLE_TYPE_CONTRACTED;
@@ -1672,7 +1718,8 @@
         if (view == null) {
             return true;
         }
-        return view.getVisibility() != VISIBLE && getViewForVisibleType(mVisibleType) != view;
+        return !isShown()
+                || (view.getVisibility() != VISIBLE && getViewForVisibleType(mVisibleType) != view);
     }
 
     @Override
@@ -1691,10 +1738,7 @@
     }
 
     public boolean isDimmable() {
-        if (!mContractedWrapper.isDimmable()) {
-            return false;
-        }
-        return true;
+        return mContractedWrapper != null && mContractedWrapper.isDimmable();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index f4ef0f8..2499952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -41,15 +42,23 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -71,14 +80,20 @@
     // Dependencies:
     private final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
+    private final StatusBarStateController mStatusBarStateController =
+            Dependency.get(StatusBarStateController.class);
+    private final DeviceProvisionedController mDeviceProvisionedController =
+            Dependency.get(DeviceProvisionedController.class);
+    private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
 
     // which notification is currently being longpress-examined by the user
+    private final IStatusBarService mBarService;
     private NotificationGuts mNotificationGutsExposed;
     private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
-    private NotificationPresenter mPresenter;
     private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
+    private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
-    private NotificationInfo.CheckSaveListener mCheckSaveListener;
+    private CheckSaveListener mCheckSaveListener;
     private OnSettingsClickListener mOnSettingsClickListener;
     @VisibleForTesting
     protected String mKeyToRemoveOnGutsClosed;
@@ -89,16 +104,17 @@
 
         mAccessibilityManager = (AccessibilityManager)
                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
             NotificationListContainer listContainer,
-            NotificationInfo.CheckSaveListener checkSaveListener,
-            OnSettingsClickListener onSettingsClickListener) {
+            CheckSaveListener checkSave, OnSettingsClickListener onSettingsClick) {
         mPresenter = presenter;
         mListContainer = listContainer;
-        mCheckSaveListener = checkSaveListener;
-        mOnSettingsClickListener = onSettingsClickListener;
+        mCheckSaveListener = checkSave;
+        mOnSettingsClickListener = onSettingsClick;
     }
 
     public void onDensityOrFontScaleChanged(ExpandableNotificationRow row) {
@@ -264,7 +280,7 @@
             onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
                 mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
                 guts.resetFalsingCheck();
-                mOnSettingsClickListener.onClick(sbn.getKey());
+                mOnSettingsClickListener.onSettingsClick(sbn.getKey());
                 startAppNotificationSettingsActivity(packageName, appUid, channel, row);
             };
         }
@@ -279,7 +295,7 @@
                 mCheckSaveListener,
                 onSettingsClick,
                 onAppSettingsClick,
-                mPresenter.isDeviceProvisioned(),
+                mDeviceProvisionedController.isDeviceProvisioned(),
                 row.getIsNonblockable(),
                 isForBlockingHelper,
                 row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
@@ -317,6 +333,10 @@
         mNotificationGutsExposed = guts;
     }
 
+    public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
+        return this::openGuts;
+    }
+
     /**
      * Opens guts on the given ExpandableNotificationRow {@code view}. This handles opening guts for
      * the normal half-swipe and long-press use cases via a circular reveal. When the blocking
@@ -385,7 +405,7 @@
                 guts.setVisibility(View.VISIBLE);
 
                 final boolean needsFalsingProtection =
-                        (mPresenter.isPresenterLocked() &&
+                        (mStatusBarStateController.getState() == StatusBarState.KEYGUARD &&
                                 !mAccessibilityManager.isTouchExplorationEnabled());
 
                 guts.openControls(
@@ -442,6 +462,6 @@
     }
 
     public interface OnSettingsClickListener {
-        void onClick(String key);
+        public void onSettingsClick(String key);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
index ea1892b..38d6b35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.row;
 
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
 
 import android.annotation.IntDef;
@@ -35,8 +36,8 @@
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.Assert;
 
@@ -102,6 +103,8 @@
 
     public static final int FLAG_CONTENT_VIEW_ALL = ~0;
 
+    // TODO: Heads up and ambient are always inflated as a temporary workaround.
+    // See http://b/117933032 and http://b/117894786
     /**
      * Content views that must be inflated at all times.
      */
@@ -109,7 +112,8 @@
     private static final int REQUIRED_INFLATION_FLAGS =
             FLAG_CONTENT_VIEW_CONTRACTED
             | FLAG_CONTENT_VIEW_EXPANDED
-            | FLAG_CONTENT_VIEW_PUBLIC;
+            | FLAG_CONTENT_VIEW_HEADS_UP
+            | FLAG_CONTENT_VIEW_AMBIENT;
 
     /**
      * The set of content views to inflate.
@@ -169,14 +173,23 @@
         mRemoteViewClickHandler = remoteViewClickHandler;
     }
 
-    public void setRedactAmbient(boolean redactAmbient) {
-        if (mRedactAmbient != redactAmbient) {
-            mRedactAmbient = redactAmbient;
-            if (mRow.getEntry() == null) {
-                return;
-            }
-            inflateNotificationViews(FLAG_CONTENT_VIEW_AMBIENT);
+    /**
+     * Update whether or not the notification is redacted on the lock screen.  If the notification
+     * is now redacted, we should inflate the public contracted view and public ambient view to
+     * now show on the lock screen.
+     *
+     * @param needsRedaction true if the notification should now be redacted on the lock screen
+     */
+    public void updateNeedsRedaction(boolean needsRedaction) {
+        mRedactAmbient = needsRedaction;
+        if (mRow.getEntry() == null) {
+            return;
         }
+        int flags = FLAG_CONTENT_VIEW_AMBIENT;
+        if (needsRedaction) {
+            flags |= FLAG_CONTENT_VIEW_PUBLIC;
+        }
+        inflateNotificationViews(flags);
     }
 
     /**
@@ -206,6 +219,17 @@
     }
 
     /**
+     * Whether or not the view corresponding to the flag is set to be inflated currently.
+     *
+     * @param flag the {@link InflationFlag} corresponding to the view
+     * @return true if the flag is set and view will be inflated, false o/w
+     */
+    @VisibleForTesting
+    public boolean isInflationFlagSet(@InflationFlag int flag) {
+        return ((mInflationFlags & flag) != 0);
+    }
+
+    /**
      * Inflate all views of this notification on a background thread. This is asynchronous and will
      * notify the callback once it's finished.
      */
@@ -230,7 +254,7 @@
             return;
         }
         // Only inflate the ones that are set.
-        reInflateFlags |= mInflationFlags;
+        reInflateFlags &= mInflationFlags;
         StatusBarNotification sbn = mRow.getEntry().notification;
         AsyncInflationTask task = new AsyncInflationTask(sbn, reInflateFlags, mCachedContentViews,
                 mRow, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight,
@@ -287,9 +311,14 @@
                     mCachedContentViews.remove(FLAG_CONTENT_VIEW_AMBIENT);
                 }
                 break;
+            case FLAG_CONTENT_VIEW_PUBLIC:
+                if (mRow.getPublicLayout().isContentViewInactive(VISIBLE_TYPE_CONTRACTED)) {
+                    mRow.getPublicLayout().setContractedChild(null);
+                    mCachedContentViews.remove(FLAG_CONTENT_VIEW_PUBLIC);
+                }
+                break;
             case FLAG_CONTENT_VIEW_CONTRACTED:
             case FLAG_CONTENT_VIEW_EXPANDED:
-            case FLAG_CONTENT_VIEW_PUBLIC:
             default:
                 break;
         }
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 659f6c7..30d1701 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
@@ -25,7 +25,6 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.WallpaperManager;
@@ -44,7 +43,6 @@
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
-
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -88,33 +86,31 @@
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
-import com.android.systemui.statusbar.notification.row.FooterView;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.NotificationSnooze;
-import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.ShadeViewRefactor;
 import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
-import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.FooterView;
+import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
+import com.android.systemui.statusbar.notification.row.NotificationGuts;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationSnooze;
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -125,6 +121,7 @@
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -195,7 +192,7 @@
     // Current padding, will be either mRegularTopPadding or mDarkTopPadding
     private int mTopPadding;
     // Distance between AOD separator and shelf
-    private int mDarkSeparatorPadding;
+    private int mDarkShelfPadding;
     private int mBottomMargin;
     private int mBottomInset = 0;
     private float mQsExpansionFraction;
@@ -424,8 +421,6 @@
     private Runnable mAnimateScroll = this::animateScroll;
     private int mCornerRadius;
     private int mSidePaddings;
-    private final int mSeparatorWidth;
-    private final int mSeparatorThickness;
     private final Rect mBackgroundAnimationRect = new Rect();
     private int mAntiBurnInOffsetX;
     private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
@@ -435,6 +430,8 @@
     private float mVerticalPanelTranslation;
     private final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
+    protected final NotificationGutsManager mGutsManager =
+            Dependency.get(NotificationGutsManager.class);
     private final Rect mTmpRect = new Rect();
     private final NotificationEntryManager mEntryManager =
             Dependency.get(NotificationEntryManager.class);
@@ -454,6 +451,7 @@
 
     private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
     private NotificationPanelView mNotificationPanel;
+    private final ShadeController mShadeController = Dependency.get(ShadeController.class);
 
     private final NotificationGutsManager
             mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
@@ -496,9 +494,7 @@
                 res.getBoolean(R.bool.config_drawNotificationBackground);
         mFadeNotificationsOnDismiss =
                 res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
-        mSeparatorWidth = res.getDimensionPixelSize(R.dimen.widget_separator_width);
-        mSeparatorThickness = res.getDimensionPixelSize(R.dimen.widget_separator_thickness);
-        mDarkSeparatorPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
+        mDarkShelfPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
         mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
         mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
         addOnExpandedHeightListener(mRoundnessManager::setExpanded);
@@ -670,23 +666,15 @@
         final int lockScreenRight = getWidth() - mSidePaddings;
         final int lockScreenTop = mCurrentBounds.top;
         final int lockScreenBottom = mCurrentBounds.bottom;
-        int separatorWidth = 0;
-        int separatorThickness = 0;
-        if (mIconAreaController.hasShelfIconsWhenFullyDark()) {
-            separatorThickness = mSeparatorThickness;
-            separatorWidth = mSeparatorWidth;
-        }
-        final int darkLeft = getWidth() / 2 - separatorWidth / 2;
-        final int darkRight = darkLeft + separatorWidth;
-        final int darkTop = (int) (mRegularTopPadding + separatorThickness / 2f);
-        final int darkBottom = darkTop + separatorThickness;
+        final int darkLeft = getWidth() / 2;
+        final int darkTop = mRegularTopPadding;
 
         if (mAmbientState.hasPulsingNotifications()) {
             // No divider, we have a notification icon instead
         } else if (mAmbientState.isFullyDark()) {
             // Only draw divider on AOD if we actually have notifications
             if (mFirstVisibleBackgroundChild != null) {
-                canvas.drawRect(darkLeft, darkTop, darkRight, darkBottom, mBackgroundPaint);
+                canvas.drawRect(darkLeft, darkTop, darkLeft, darkTop, mBackgroundPaint);
             }
         } else {
             float yProgress = 1 - mInterpolatedDarkAmount;
@@ -696,8 +684,8 @@
             mBackgroundAnimationRect.set(
                     (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress),
                     (int) MathUtils.lerp(darkTop, lockScreenTop, yProgress),
-                    (int) MathUtils.lerp(darkRight, lockScreenRight, xProgress),
-                    (int) MathUtils.lerp(darkBottom, lockScreenBottom, yProgress));
+                    (int) MathUtils.lerp(darkLeft, lockScreenRight, xProgress),
+                    (int) MathUtils.lerp(darkTop, lockScreenBottom, yProgress));
 
             if (!mAmbientState.isDark() || mFirstVisibleBackgroundChild != null) {
                 canvas.drawRoundRect(mBackgroundAnimationRect.left, mBackgroundAnimationRect.top,
@@ -1010,7 +998,7 @@
     private void setTopPadding(int topPadding, boolean animate) {
         if (mRegularTopPadding != topPadding) {
             mRegularTopPadding = topPadding;
-            mDarkTopPadding = topPadding + mDarkSeparatorPadding;
+            mDarkTopPadding = topPadding + mDarkShelfPadding;
             mAmbientState.setDarkTopPadding(mDarkTopPadding);
             updateAlgorithmHeightAndPadding();
             updateContentHeight();
@@ -4740,7 +4728,8 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void setStatusBarState(int statusBarState) {
+    @VisibleForTesting
+    protected void setStatusBarState(int statusBarState) {
         mStatusBarState = statusBarState;
         mAmbientState.setStatusBarState(statusBarState);
     }
@@ -4942,7 +4931,7 @@
             return;
         }
 
-        mStatusBar.addPostCollapseAction(() -> {
+        mShadeController.addPostCollapseAction(() -> {
             setDismissAllInProgress(false);
             for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
                 if (canChildBeDismissed(rowToRemove)) {
@@ -5042,6 +5031,10 @@
         mNotificationPanel = notificationPanelView;
     }
 
+    public void updateIconAreaViews() {
+        mIconAreaController.updateNotificationIcons();
+    }
+
     /**
      * A listener that is notified when the empty space below the notifications is clicked on
      */
@@ -5662,7 +5655,7 @@
 
                 if (mNotificationPanel.onDraggedDown() || startingChild != null) {
                     // We have notifications, go to locked shade.
-                    mStatusBar.goToLockedShade(startingChild);
+                    mShadeController.goToLockedShade(startingChild);
                     if (startingChild instanceof ExpandableNotificationRow) {
                         ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
                         row.onExpandedByGesture(true /* drag down is always an open */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index c094669..8325bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -32,6 +32,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.NotificationMediaManager;
 
 import java.io.PrintWriter;
 
@@ -95,6 +96,8 @@
      */
     private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
 
+    private final NotificationMediaManager mMediaManager =
+            Dependency.get(NotificationMediaManager.class);
     private PowerManager mPowerManager;
     private Handler mHandler = new Handler();
     private PowerManager.WakeLock mWakeLock;
@@ -264,7 +267,7 @@
             case MODE_WAKE_AND_UNLOCK:
                 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
                     Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
-                    mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
+                    mMediaManager.updateMediaMetaData(false /* metaDataChanged */,
                             true /* allowEnterAnimation */);
                 } else if (mMode == MODE_WAKE_AND_UNLOCK){
                     Trace.beginSection("MODE_WAKE_AND_UNLOCK");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 587b40d..4eca6bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -288,4 +288,10 @@
             }
         }
     }
+
+    /**
+     * Executes when button is detached from window.
+     */
+    protected void onDestroy() {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index a781be6..fa63831 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -64,11 +64,12 @@
     private StatusBar mStatusBarComponent;
     private DarkIconManager mDarkIconManager;
     private View mOperatorNameFrame;
+    private CommandQueue mCommandQueue;
 
     private SignalCallback mSignalCallback = new SignalCallback() {
         @Override
         public void setIsAirplaneMode(NetworkController.IconState icon) {
-            mStatusBarComponent.recomputeDisableFlags(true /* animate */);
+            mCommandQueue.recomputeDisableFlags(true /* animate */);
         }
     };
 
@@ -78,6 +79,7 @@
         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
         mNetworkController = Dependency.get(NetworkController.class);
         mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
+        mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
     }
 
     @Override
@@ -116,13 +118,13 @@
     @Override
     public void onResume() {
         super.onResume();
-        SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+        mCommandQueue.addCallbacks(this);
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
+        mCommandQueue.removeCallbacks(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
index c7ab27b..5dded52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -18,8 +18,10 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.view.View;
+
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.KeyButtonView;
 
@@ -29,6 +31,9 @@
  */
 public class ContextualButton extends ButtonDispatcher {
 
+    private ContextButtonListener mListener;
+    private ContextualButtonGroup mGroup;
+
     protected final @DrawableRes int mIconResId;
 
     /**
@@ -64,6 +69,48 @@
             currentDrawable.clearAnimationCallbacks();
             currentDrawable.resetAnimation();
         }
+
+        if (mListener != null) {
+            mListener.onVisibilityChanged(this, visibility == View.VISIBLE);
+        }
+    }
+
+    public void setListener(ContextButtonListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Show this button based on its priority compared to other buttons in the group. If not
+     * attached to a group it will set its own visibility to be visible.
+     * @return if visible
+     */
+    public boolean show() {
+        if (mGroup == null) {
+            setVisibility(View.VISIBLE);
+            return true;
+        }
+        return mGroup.setButtonVisiblity(getId(), true /* visible */) == View.VISIBLE;
+    }
+
+    /**
+     * Hide this button.
+     * @return if visible
+     */
+    public boolean hide() {
+        if (mGroup == null) {
+            setVisibility(View.INVISIBLE);
+            return false;
+        }
+        return mGroup.setButtonVisiblity(getId(), false /* visible */) != View.VISIBLE;
+    }
+
+    /**
+     * Called when this button was added to the group. Keep a reference to the group to show based
+     * on priority compared to other buttons.
+     * @param group the holder of all the buttons
+     */
+    void attachToGroup(@NonNull ContextualButtonGroup group) {
+        mGroup = group;
     }
 
     protected KeyButtonDrawable getNewDrawable() {
@@ -79,4 +126,8 @@
     protected Context getContext() {
         return getCurrentView().getContext();
     }
+
+    public interface ContextButtonListener {
+        void onVisibilityChanged(ContextualButton button, boolean visible);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
index 1b03966..9703043 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
@@ -40,6 +40,7 @@
      * @param button the button added to the group
      */
     public void addButton(@NonNull ContextualButton button) {
+        button.attachToGroup(this);
         mButtonData.add(new ButtonData(button));
     }
 
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 072343a..5439497 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -63,6 +63,7 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -228,6 +229,11 @@
         }
     };
 
+    public void initFrom(KeyguardBottomAreaView oldBottomArea) {
+        setKeyguardIndicationController(oldBottomArea.mIndicationController);
+        setStatusBar(oldBottomArea.mStatusBar);
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -578,7 +584,8 @@
         }
     }
 
-    private void launchVoiceAssist() {
+    @VisibleForTesting
+    void launchVoiceAssist() {
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
@@ -787,6 +794,10 @@
         mIndicationController = keyguardIndicationController;
     }
 
+    public void showTransientIndication(int id) {
+        mIndicationController.showTransientIndication(id);
+    }
+
     public void updateLeftAffordance() {
         updateLeftAffordanceIcon();
         updateLeftPreview();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 8ac8677..235629b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 
 import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 836a55f..4a7bc3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -145,7 +145,7 @@
         final int y = getClockY();
         result.clockY = y;
         result.clockAlpha = getClockAlpha(y);
-        result.stackScrollerPadding = y + (mPulsing ? 0 : mKeyguardStatusHeight);
+        result.stackScrollerPadding = y + (mPulsing ? mPulsingPadding : mKeyguardStatusHeight);
         result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index 76ddca4..6111178 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -16,9 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.annotation.Nullable;
-
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 
 /** Executes actions that require the screen to be unlocked. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index d676692..462201c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -18,7 +18,7 @@
 
 import android.util.Log;
 
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 /**
  * Executes actions that require the screen to be unlocked. Delegates the actual handling to an
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
new file mode 100644
index 0000000..b3423a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
+import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
+
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
+
+    private static final String TAG = "KeyguardEnvironmentImpl";
+
+    private final NotificationLockscreenUserManager mLockscreenUserManager =
+            Dependency.get(NotificationLockscreenUserManager.class);
+    private final DeviceProvisionedController mDeviceProvisionedController =
+            Dependency.get(DeviceProvisionedController.class);
+    private final NotificationMediaManager mMediaManager =
+            Dependency.get(NotificationMediaManager.class);
+
+    public KeyguardEnvironmentImpl() {
+    }
+
+    @Override  // NotificationData.KeyguardEnvironment
+    public boolean isDeviceProvisioned() {
+        return mDeviceProvisionedController.isDeviceProvisioned();
+    }
+
+    @Override  // NotificationData.KeyguardEnvironment
+    public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
+        final int notificationUserId = n.getUserId();
+        if (DEBUG && MULTIUSER_DEBUG) {
+            Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
+                    mLockscreenUserManager.getCurrentUserId(), notificationUserId));
+        }
+        return mLockscreenUserManager.isCurrentProfile(notificationUserId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 40ddf5b..673cdb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -40,6 +40,8 @@
 import android.util.Log;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationMediaManager;
 
 import libcore.io.IoUtils;
 
@@ -52,6 +54,9 @@
 
     private static final String TAG = "LockscreenWallpaper";
 
+    private final NotificationMediaManager mMediaManager =
+            Dependency.get(NotificationMediaManager.class);
+
     private final StatusBar mBar;
     private final WallpaperManager mWallpaperManager;
     private final Handler mH;
@@ -193,7 +198,7 @@
                     mCached = true;
                     mCache = result.bitmap;
                     mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
-                    mBar.updateMediaMetaData(
+                    mMediaManager.updateMediaMetaData(
                             true /* metaDataChanged */, true /* allowEnterAnimation */);
                 }
                 mLoader = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 80f3506..6edde07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -19,26 +19,20 @@
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
 
-import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
-
+import static com.android.systemui.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
 import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
-import static com.android.systemui.OverviewProxyService.OverviewProxyListener;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.annotation.IdRes;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.Fragment;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
@@ -55,11 +49,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
-import androidx.annotation.VisibleForTesting;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -72,16 +64,16 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
 import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
@@ -90,21 +82,20 @@
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.KeyButtonDrawable;
-import com.android.systemui.statusbar.policy.KeyButtonView;
-import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyButtonView;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
 import java.util.Locale;
-import java.util.Optional;
+import java.util.function.Consumer;
 
 /**
  * Fragment containing the NavigationBarFragment. Contains logic for what happens
@@ -114,18 +105,15 @@
 
     public static final String TAG = "NavigationBar";
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_ROTATION = true;
     private static final String EXTRA_DISABLE_STATE = "disabled_state";
     private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
 
-    private final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
-    private final static int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
-
-    private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
-
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
+    private final DeviceProvisionedController mDeviceProvisionedController =
+            Dependency.get(DeviceProvisionedController.class);
+
     protected NavigationBarView mNavigationBarView = null;
     protected AssistManager mAssistManager;
 
@@ -133,7 +121,6 @@
 
     private int mNavigationIconHints = 0;
     private int mNavigationBarMode;
-    private boolean mAccessibilityFeedbackEnabled;
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
@@ -158,18 +145,6 @@
 
     public boolean mHomeBlockedThisTouch;
 
-    private int mLastRotationSuggestion;
-    private boolean mPendingRotationSuggestion;
-    private boolean mHoveringRotationSuggestion;
-    private RotationLockController mRotationLockController;
-    private TaskStackListenerImpl mTaskStackListener;
-
-    private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false);
-    private final Runnable mCancelPendingRotationProposal =
-            () -> mPendingRotationSuggestion = false;
-    private Animator mRotateHideAnimator;
-    private ViewRippler mViewRippler = new ViewRippler();
-
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
@@ -180,7 +155,7 @@
         @Override
         public void onQuickStepStarted() {
             // Use navbar dragging as a signal to hide the rotate button
-            setRotateSuggestionButtonState(false);
+            mNavigationBarView.getRotateSuggestionButton().setRotateSuggestionButtonState(false);
 
             // Hide the notifications panel when quick step starts
             mStatusBar.collapsePanel(true /* animate */);
@@ -206,6 +181,17 @@
         }
     };
 
+    private final ContextButtonListener mRotationButtonListener = new ContextButtonListener() {
+        @Override
+        public void onVisibilityChanged(ContextualButton button, boolean visible) {
+            if (visible) {
+                // If the button will actually become visible and the navbar is about to hide,
+                // tell the statusbar to keep it around for longer
+                mStatusBar.touchAutoHide();
+            }
+        }
+    };
+
     // ----- Fragment Lifecycle Callbacks -----
 
     @Override
@@ -233,26 +219,6 @@
         }
         mAssistManager = Dependency.get(AssistManager.class);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
-
-        try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .watchRotation(mRotationWatcher, getContext().getDisplayId());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-        mRotationLockController = Dependency.get(RotationLockController.class);
-
-        // Reset user rotation pref to match that of the WindowManager if starting in locked mode
-        // This will automatically happen when switching from auto-rotate to locked mode
-        if (mRotationLockController.isRotationLocked()) {
-            final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
-            mRotationLockController.setRotationLockedAtAngle(true, winRotation);
-        }
-
-        // Register the task stack listener
-        mTaskStackListener = new TaskStackListenerImpl();
-        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
     }
 
     @Override
@@ -262,15 +228,6 @@
         Dependency.get(AccessibilityManagerWrapper.class).removeCallback(
                 mAccessibilityListener);
         mContentResolver.unregisterContentObserver(mMagnificationObserver);
-        try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .removeRotationWatcher(mRotationWatcher);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-        // Unregister the task stack listener
-        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
     }
 
     @Override
@@ -303,6 +260,17 @@
         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
         notifyNavigationBarScreenOn();
         mOverviewProxyService.addCallback(mOverviewProxyListener);
+
+        RotationContextButton rotationButton = mNavigationBarView.getRotateSuggestionButton();
+        rotationButton.setListener(mRotationButtonListener);
+        rotationButton.addRotationCallback(mRotationWatcher);
+
+        // Reset user rotation pref to match that of the WindowManager if starting in locked mode
+        // This will automatically happen when switching from auto-rotate to locked mode
+        if (rotationButton.isRotationLocked()) {
+            final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
+            rotationButton.setRotationLockedAtAngle(winRotation);
+        }
     }
 
     @Override
@@ -413,229 +381,31 @@
             mNavigationBarWindowState = state;
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
 
-            // If the navbar is visible, show the rotate button if there's a pending suggestion
-            if (state == WINDOW_STATE_SHOWING && mPendingRotationSuggestion) {
-                showAndLogRotationSuggestion();
-            }
+            mNavigationBarView.getRotateSuggestionButton()
+                    .onNavigationBarWindowVisibilityChange(state == WINDOW_STATE_SHOWING);
         }
     }
 
     @Override
     public void onRotationProposal(final int rotation, boolean isValid) {
         final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
-        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(mDisabledFlags2);
-        if (DEBUG_ROTATION) {
+        final boolean rotateSuggestionsDisabled = RotationContextButton
+                .hasDisable2RotateSuggestionFlag(mDisabledFlags2);
+        if (RotationContextButton.DEBUG_ROTATION) {
             Log.v(TAG, "onRotationProposal proposedRotation=" + Surface.rotationToString(rotation)
                     + ", winRotation=" + Surface.rotationToString(winRotation)
                     + ", isValid=" + isValid + ", mNavBarWindowState="
                     + StatusBarManager.windowStateToString(mNavigationBarWindowState)
                     + ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
                     + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null" :
-                        mNavigationBarView.isRotateButtonVisible()));
+                        mNavigationBarView.getRotateSuggestionButton().isVisible()));
         }
 
         // Respect the disabled flag, no need for action as flag change callback will handle hiding
         if (rotateSuggestionsDisabled) return;
 
-        // This method will be called on rotation suggestion changes even if the proposed rotation
-        // is not valid for the top app. Use invalid rotation choices as a signal to remove the
-        // rotate button if shown.
-        if (!isValid) {
-            setRotateSuggestionButtonState(false);
-            return;
-        }
-
-        // If window rotation matches suggested rotation, remove any current suggestions
-        if (rotation == winRotation) {
-            getView().removeCallbacks(mRemoveRotationProposal);
-            setRotateSuggestionButtonState(false);
-            return;
-        }
-
-        // Prepare to show the navbar icon by updating the icon style to change anim params
-        mLastRotationSuggestion = rotation; // Remember rotation for click
-        if (mNavigationBarView != null) {
-            final boolean rotationCCW = isRotationAnimationCCW(winRotation, rotation);
-            int style;
-            if (winRotation == Surface.ROTATION_0 || winRotation == Surface.ROTATION_180) {
-                style = rotationCCW ? R.style.RotateButtonCCWStart90 :
-                        R.style.RotateButtonCWStart90;
-            } else { // 90 or 270
-                style = rotationCCW ? R.style.RotateButtonCCWStart0 :
-                        R.style.RotateButtonCWStart0;
-            }
-            mNavigationBarView.updateRotateSuggestionButtonStyle(style);
-        }
-
-        if (mNavigationBarWindowState != WINDOW_STATE_SHOWING) {
-            // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
-            // visible given some time limit.
-            mPendingRotationSuggestion = true;
-            getView().removeCallbacks(mCancelPendingRotationProposal);
-            getView().postDelayed(mCancelPendingRotationProposal,
-                    NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
-
-        } else { // The navbar is visible so show the icon right away
-            showAndLogRotationSuggestion();
-        }
-    }
-
-    private void onRotationSuggestionsDisabled() {
-        // Immediately hide the rotate button and clear any planned removal
-        setRotateSuggestionButtonState(false, true);
-
-        // This method can be called before view setup is done, ensure getView isn't null
-        final View v = getView();
-        if (v != null) v.removeCallbacks(mRemoveRotationProposal);
-    }
-
-    private void showAndLogRotationSuggestion() {
-        setRotateSuggestionButtonState(true);
-        rescheduleRotationTimeout(false);
-        mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
-    }
-
-    private boolean isRotationAnimationCCW(int from, int to) {
-        // All 180deg WM rotation animations are CCW, match that
-        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false;
-        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW
-        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true;
-        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true;
-        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false;
-        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW
-        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW
-        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true;
-        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false;
-        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false;
-        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW
-        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true;
-        return false; // Default
-    }
-
-    public void setRotateSuggestionButtonState(final boolean visible) {
-        setRotateSuggestionButtonState(visible, false);
-    }
-
-    public void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
-        if (mNavigationBarView == null) return;
-
-        // At any point the the button can become invisible because an a11y service became active.
-        // Similarly, a call to make the button visible may be rejected because an a11y service is
-        // active. Must account for this.
-
-        ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton();
-        final boolean currentlyVisible = mNavigationBarView.isRotateButtonVisible();
-
-        // Rerun a show animation to indicate change but don't rerun a hide animation
-        if (!visible && !currentlyVisible) return;
-
-        View view = rotBtn.getCurrentView();
-        if (view == null) return;
-
-        KeyButtonDrawable kbd = rotBtn.getImageDrawable();
-        if (kbd == null) return;
-
-        // Clear any pending suggestion flag as it has either been nullified or is being shown
-        mPendingRotationSuggestion = false;
-        if (getView() != null) getView().removeCallbacks(mCancelPendingRotationProposal);
-
-        // Handle the visibility change and animation
-        if (visible) { // Appear and change (cannot force)
-            // Stop and clear any currently running hide animations
-            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
-                mRotateHideAnimator.cancel();
-            }
-            mRotateHideAnimator = null;
-
-            // Reset the alpha if any has changed due to hide animation
-            view.setAlpha(1f);
-
-            // Run the rotate icon's animation if it has one
-            if (kbd.canAnimate()) {
-                kbd.resetAnimation();
-                kbd.startAnimation();
-            }
-
-            if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
-
-            // Set visibility, may fail if a11y service is active.
-            // If invisible, call will stop animation.
-            int appliedVisibility = mNavigationBarView.setRotateButtonVisibility(true);
-            if (appliedVisibility == View.VISIBLE) {
-                // If the button will actually become visible and the navbar is about to hide,
-                // tell the statusbar to keep it around for longer
-                mStatusBar.touchAutoHide();
-            }
-
-        } else { // Hide
-
-            mViewRippler.stop(); // Prevent any pending ripples, force hide or not
-
-            if (force) {
-                // If a hide animator is running stop it and make invisible
-                if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
-                    mRotateHideAnimator.pause();
-                }
-                mNavigationBarView.setRotateButtonVisibility(false);
-                return;
-            }
-
-            // Don't start any new hide animations if one is running
-            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
-
-            ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha",
-                    0f);
-            fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
-            fadeOut.setInterpolator(Interpolators.LINEAR);
-            fadeOut.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mNavigationBarView.setRotateButtonVisibility(false);
-                }
-            });
-
-            mRotateHideAnimator = fadeOut;
-            fadeOut.start();
-        }
-    }
-
-    private void rescheduleRotationTimeout(final boolean reasonHover) {
-        // May be called due to a new rotation proposal or a change in hover state
-        if (reasonHover) {
-            // Don't reschedule if a hide animator is running
-            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
-            // Don't reschedule if not visible
-            if (!mNavigationBarView.isRotateButtonVisible()) return;
-        }
-
-        getView().removeCallbacks(mRemoveRotationProposal); // Stop any pending removal
-        getView().postDelayed(mRemoveRotationProposal,
-                computeRotationProposalTimeout()); // Schedule timeout
-    }
-
-    private int computeRotationProposalTimeout() {
-        if (mAccessibilityFeedbackEnabled) return 20000;
-        if (mHoveringRotationSuggestion) return 16000;
-        return 10000;
-    }
-
-    private boolean isRotateSuggestionIntroduced() {
-        ContentResolver cr = getContext().getContentResolver();
-        return Settings.Secure.getInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0)
-                >= NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION;
-    }
-
-    private void incrementNumAcceptedRotationSuggestionsIfNeeded() {
-        // Get the number of accepted suggestions
-        ContentResolver cr = getContext().getContentResolver();
-        final int numSuggestions = Settings.Secure.getInt(cr,
-                Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0);
-
-        // Increment the number of accepted suggestions only if it would change intro mode
-        if (numSuggestions < NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION) {
-            Settings.Secure.putInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
-                    numSuggestions + 1);
-        }
+        mNavigationBarView.getRotateSuggestionButton()
+                .onRotationProposal(rotation, winRotation, isValid);
     }
 
     // Injected from StatusBar at creation.
@@ -708,12 +478,7 @@
 
     private void setDisabled2Flags(int state2) {
         // Method only called on change of disable2 flags
-        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
-        if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
-    }
-
-    private boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
-        return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
+        mNavigationBarView.getRotateSuggestionButton().onDisable2FlagChanged(state2);
     }
 
     // ----- Internal stuffz -----
@@ -725,7 +490,7 @@
     }
 
     private boolean shouldDisableNavbarGestures() {
-        return !mStatusBar.isDeviceProvisioned()
+        return !mDeviceProvisionedController.isDeviceProvisioned()
                 || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
@@ -778,9 +543,6 @@
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
         updateAccessibilityServicesState(mAccessibilityManager);
 
-        ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
-        rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
-        rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
         updateScreenPinningGestures();
     }
 
@@ -1000,27 +762,14 @@
             }
         }
 
-        mAccessibilityFeedbackEnabled = feedbackEnabled;
+        mNavigationBarView.getRotateSuggestionButton()
+                .setAccessibilityFeedbackEnabled(feedbackEnabled);
 
         final boolean showAccessibilityButton = requestingServices >= 1;
         final boolean targetSelection = requestingServices >= 2;
         mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
     }
 
-    private void onRotateSuggestionClick(View v) {
-        mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
-        incrementNumAcceptedRotationSuggestionsIfNeeded();
-        mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
-    }
-
-    private boolean onRotateSuggestionHover(View v, MotionEvent event) {
-        final int action = event.getActionMasked();
-        mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
-                || (action == MotionEvent.ACTION_HOVER_MOVE);
-        rescheduleRotationTimeout(true);
-        return false; // Must return false so a11y hover events are dispatched correctly.
-    }
-
     // ----- Methods that StatusBar talks to (should be minimized) -----
 
     public void setLightBarController(LightBarController lightBarController) {
@@ -1066,36 +815,10 @@
         }
     }
 
-    private final Stub mRotationWatcher = new Stub() {
-        @Override
-        public void onRotationChanged(final int rotation) throws RemoteException {
-            // We need this to be scheduled as early as possible to beat the redrawing of
-            // window in response to the orientation change.
-            Handler h = getView().getHandler();
-            Message msg = Message.obtain(h, () -> {
-
-                // If the screen rotation changes while locked, potentially update lock to flow with
-                // new screen rotation and hide any showing suggestions.
-                if (mRotationLockController.isRotationLocked()) {
-                    if (shouldOverrideUserLockPrefs(rotation)) {
-                        mRotationLockController.setRotationLockedAtAngle(true, rotation);
-                    }
-                    setRotateSuggestionButtonState(false, true);
-                }
-
-                if (mNavigationBarView != null
-                        && mNavigationBarView.needsReorient(rotation)) {
-                    repositionNavigationBar();
-                }
-            });
-            msg.setAsynchronous(true);
-            h.sendMessageAtFrontOfQueue(msg);
-        }
-
-        private boolean shouldOverrideUserLockPrefs(final int rotation) {
-            // Only override user prefs when returning to the natural rotation (normally portrait).
-            // Don't let apps that force landscape or 180 alter user lock.
-            return rotation == NATURAL_ROTATION;
+    private final Consumer<Integer> mRotationWatcher = rotation -> {
+        if (mNavigationBarView != null
+                && mNavigationBarView.needsReorient(rotation)) {
+            repositionNavigationBar();
         }
     };
 
@@ -1114,69 +837,6 @@
         }
     };
 
-    class TaskStackListenerImpl extends TaskStackChangeListener {
-        // Invalidate any rotation suggestion on task change or activity orientation change
-        // Note: all callbacks happen on main thread
-
-        @Override
-        public void onTaskStackChanged() {
-            setRotateSuggestionButtonState(false);
-        }
-
-        @Override
-        public void onTaskRemoved(int taskId) {
-            setRotateSuggestionButtonState(false);
-        }
-
-        @Override
-        public void onTaskMovedToFront(int taskId) {
-            setRotateSuggestionButtonState(false);
-        }
-
-        @Override
-        public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
-            // Only hide the icon if the top task changes its requestedOrientation
-            // Launcher can alter its requestedOrientation while it's not on top, don't hide on this
-            Optional.ofNullable(ActivityManagerWrapper.getInstance())
-                    .map(ActivityManagerWrapper::getRunningTask)
-                    .ifPresent(a -> {
-                        if (a.id == taskId) setRotateSuggestionButtonState(false);
-                    });
-        }
-    }
-
-    private class ViewRippler {
-        private static final int RIPPLE_OFFSET_MS = 50;
-        private static final int RIPPLE_INTERVAL_MS = 2000;
-        private View mRoot;
-
-        public void start(View root) {
-            stop(); // Stop any pending ripple animations
-
-            mRoot = root;
-
-            // Schedule pending ripples, offset the 1st to avoid problems with visibility change
-            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
-            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
-            mRoot.postOnAnimationDelayed(mRipple, 2*RIPPLE_INTERVAL_MS);
-            mRoot.postOnAnimationDelayed(mRipple, 3*RIPPLE_INTERVAL_MS);
-            mRoot.postOnAnimationDelayed(mRipple, 4*RIPPLE_INTERVAL_MS);
-        }
-
-        public void stop() {
-            if (mRoot != null) mRoot.removeCallbacks(mRipple);
-        }
-
-        private final Runnable mRipple = new Runnable() {
-            @Override
-            public void run() { // Cause the ripple to fire via false presses
-                if (!mRoot.isAttachedToWindow()) return;
-                mRoot.setPressed(true);
-                mRoot.setPressed(false);
-            }
-        };
-    }
-
     public static View create(Context context, FragmentListener listener) {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e92656ae..2ab5958 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -29,7 +29,6 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.DrawableRes;
-import android.annotation.StyleRes;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -271,7 +270,7 @@
         final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
                 R.drawable.ic_ime_switcher_default);
         final RotationContextButton rotateSuggestionButton = new RotationContextButton(
-                R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button,
+                R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button, getContext(),
                 R.style.RotateButtonCCWStart90);
         final ContextualButton accessibilityButton =
                 new ContextualButton(R.id.accessibility_button,
@@ -350,7 +349,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         shouldDeadZoneConsumeTouchEvents(event);
-        if (mGestureHelper.onTouchEvent(event)) {
+        if (mGestureHelper != null && mGestureHelper.onTouchEvent(event)) {
             return true;
         }
         return super.onTouchEvent(event);
@@ -418,8 +417,9 @@
         return mButtonDispatchers.get(R.id.accessibility_button);
     }
 
-    public ButtonDispatcher getRotateSuggestionButton() {
-        return mButtonDispatchers.get(R.id.rotate_suggestion);
+    public RotationContextButton getRotateSuggestionButton() {
+        return (RotationContextButton) mContextualButtonGroup
+                .getContextButton(R.id.rotate_suggestion);
     }
 
     public SparseArray<ButtonDispatcher> getButtonDispatchers() {
@@ -680,7 +680,9 @@
     }
 
     public void onNavigationButtonLongPress(View v) {
-        mGestureHelper.onNavigationButtonLongPress(v);
+        if (mGestureHelper != null) {
+            mGestureHelper.onNavigationButtonLongPress(v);
+        }
     }
 
     public void onPanelExpandedChange(boolean expanded) {
@@ -744,27 +746,12 @@
         mContextualButtonGroup.setButtonVisiblity(R.id.menu, show);
     }
 
-    public void updateRotateSuggestionButtonStyle(@StyleRes int style) {
-        RotationContextButton button = (RotationContextButton) mContextualButtonGroup
-                .getContextButton(R.id.rotate_suggestion);
-        button.setStyle(style);
-        button.updateIcon();
-    }
-
     public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
         mLongClickableAccessibilityButton = longClickable;
         getAccessibilityButton().setLongClickable(longClickable);
         mContextualButtonGroup.setButtonVisiblity(R.id.accessibility_button, visible);
     }
 
-    public int setRotateButtonVisibility(boolean visible) {
-        return mContextualButtonGroup.setButtonVisiblity(R.id.rotate_suggestion, visible);
-    }
-
-    public boolean isRotateButtonVisible() {
-        return getRotateSuggestionButton().isVisible();
-    }
-
     void hideRecentsOnboarding() {
         mRecentsOnboarding.hide(true);
     }
@@ -807,7 +794,9 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        mGestureHelper.onDraw(canvas);
+        if (mGestureHelper != null) {
+            mGestureHelper.onDraw(canvas);
+        }
         mDeadZone.onDraw(canvas);
         super.onDraw(canvas);
     }
@@ -819,7 +808,9 @@
         updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
         updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
         updateButtonLocationOnScreen(getRotateSuggestionButton(), mRotationButtonBounds);
-        mGestureHelper.onLayout(changed, left, top, right, bottom);
+        if (mGestureHelper != null) {
+            mGestureHelper.onLayout(changed, left, top, right, bottom);
+        }
         mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
     }
 
@@ -1052,6 +1043,9 @@
             mGestureHelper.destroy();
         }
         setUpSwipeUpOnboarding(false);
+        for (int i = 0; i < mButtonDispatchers.size(); ++i) {
+            mButtonDispatchers.valueAt(i).onDestroy();
+        }
     }
 
     private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
@@ -1117,7 +1111,9 @@
         pw.println("    }");
 
         mContextualButtonGroup.dump(pw);
-        mGestureHelper.dump(pw);
+        if (mGestureHelper != null) {
+            mGestureHelper.dump(pw);
+        }
         mRecentsOnboarding.dump(pw);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index b19f57d0..21b98db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -49,7 +49,6 @@
     private ViewGroup mNotificationScrollLayout;
     private Context mContext;
     private boolean mFullyDark;
-    private boolean mHasShelfIconsWhenFullyDark;
 
     public NotificationIconAreaController(Context context, StatusBar statusBar) {
         mStatusBar = statusBar;
@@ -176,33 +175,10 @@
 
         updateStatusBarIcons();
         updateShelfIcons();
-        updateHasShelfIconsWhenFullyDark();
 
         applyNotificationIconsTint();
     }
 
-    private void updateHasShelfIconsWhenFullyDark() {
-        boolean hasIconsWhenFullyDark = false;
-        for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
-            View view = mNotificationScrollLayout.getChildAt(i);
-            if (view instanceof ExpandableNotificationRow) {
-                NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
-                if (shouldShowNotificationIcon(ent,
-                        NotificationShelf.SHOW_AMBIENT_ICONS /* showAmbient */,
-                        false /* hideDismissed */,
-                        true /* hideReplied */)) {
-                    hasIconsWhenFullyDark = true;
-                    break;
-                }
-            }
-        }
-        mHasShelfIconsWhenFullyDark = hasIconsWhenFullyDark;
-    }
-
-    public boolean hasShelfIconsWhenFullyDark() {
-        return mHasShelfIconsWhenFullyDark;
-    }
-
     private void updateShelfIcons() {
         updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
                 NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index e31bad65..31facb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.SysUiServiceProvider.getComponent;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
         .ExpandAnimationParameters;
 
@@ -65,10 +66,12 @@
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFragment;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
@@ -337,6 +340,11 @@
             Dependency.get(NotificationEntryManager.class);
 
     private final StateListener mListener = this::setBarState;
+    private final CommandQueue mCommandQueue;
+    private final NotificationLockscreenUserManager mLockscreenUserManager =
+            Dependency.get(NotificationLockscreenUserManager.class);
+    private final ShadeController mShadeController =
+            Dependency.get(ShadeController.class);
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -347,6 +355,7 @@
         setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
         mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
         setPanelAlpha(255, false /* animate */);
+        mCommandQueue = getComponent(context, CommandQueue.class);
     }
 
     private void setStatusBar(StatusBar bar) {
@@ -458,10 +467,12 @@
         // Update keyguard bottom area
         index = indexOfChild(mKeyguardBottomArea);
         removeView(mKeyguardBottomArea);
+        KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea;
         mKeyguardBottomArea = (KeyguardBottomAreaView) LayoutInflater.from(mContext).inflate(
                 R.layout.keyguard_bottom_area,
                 this,
                 false);
+        mKeyguardBottomArea.initFrom(oldBottomArea);
         addView(mKeyguardBottomArea, index);
         initBottomArea();
         setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount);
@@ -630,7 +641,7 @@
             if (suppressedSummary) {
                 continue;
             }
-            if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard(
+            if (!mLockscreenUserManager.shouldShowOnKeyguard(
                     row.getStatusBarNotification())) {
                 continue;
             }
@@ -2414,7 +2425,7 @@
                 return true;
             case StatusBarState.SHADE_LOCKED:
                 if (!mQsExpanded) {
-                    mStatusBar.goToKeyguard();
+                    mShadeController.goToKeyguard();
                 }
                 return true;
             case StatusBarState.SHADE:
@@ -2617,7 +2628,7 @@
         }
         if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
             mShowIconsWhenExpanded = showIconsWhenExpanded;
-            mStatusBar.recomputeDisableFlags(false);
+            mCommandQueue.recomputeDisableFlags(false);
         }
     }
 
@@ -2904,7 +2915,7 @@
             if (hideIcons != mHideIconsDuringNotificationLaunch) {
                 mHideIconsDuringNotificationLaunch = hideIcons;
                 if (!hideIcons) {
-                    mStatusBar.recomputeDisableFlags(true /* animate */);
+                    mCommandQueue.recomputeDisableFlags(true /* animate */);
                 }
             }
         }
@@ -2972,6 +2983,7 @@
         mNotificationStackScroller.updateSpeedBumpIndex();
         mNotificationStackScroller.updateFooter();
         updateShowEmptyShadeView();
+        mNotificationStackScroller.updateIconAreaViews();
     }
 
     public void onUpdateRowStates() {
@@ -3019,6 +3031,10 @@
         updateShowEmptyShadeView();
     }
 
+    public void showTransientIndication(int id) {
+        mKeyguardBottomArea.showTransientIndication(id);
+    }
+
     /**
      * Whenever a user drags down on the empty area (pulling down the shade and clock) and lets go.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 59863ec..2129835 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,6 +19,7 @@
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+import static com.android.systemui.SysUiServiceProvider.getComponent;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -42,6 +43,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
@@ -52,6 +54,7 @@
     private static final boolean DEBUG = StatusBar.DEBUG;
     private static final boolean DEBUG_GESTURES = false;
     private static final int NO_VALUE = Integer.MIN_VALUE;
+    private final CommandQueue mCommandQueue;
 
     StatusBar mBar;
 
@@ -82,6 +85,7 @@
         super(context, attrs);
 
         mBarTransitions = new PhoneStatusBarTransitions(this);
+        mCommandQueue = getComponent(context, CommandQueue.class);
     }
 
     public BarTransitions getBarTransitions() {
@@ -166,7 +170,7 @@
 
     @Override
     public boolean panelEnabled() {
-        return mBar.panelsEnabled();
+        return mCommandQueue.panelsEnabled();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index 15e189c..855592f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -16,29 +16,269 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.NonNull;
 import android.annotation.StyleRes;
+import android.app.StatusBarManager;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.ContextWrapper;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
 import android.view.ContextThemeWrapper;
+import android.view.IRotationWatcher.Stub;
+import android.view.MotionEvent;
+import android.view.Surface;
 import android.view.View;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
-import com.android.systemui.util.Utils;
+import com.android.systemui.statusbar.policy.RotationLockController;
+
+import java.util.Optional;
+import java.util.function.Consumer;
 
 public class RotationContextButton extends ContextualButton {
+    public static final boolean DEBUG_ROTATION = false;
+
+    private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
+    private static final int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
+
+    private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
 
     private @StyleRes int mStyleRes;
 
-    public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId,
-            @StyleRes int style) {
-        super(buttonResId, iconResId);
-        mStyleRes = style;
+    private int mLastRotationSuggestion;
+    private boolean mPendingRotationSuggestion;
+    private boolean mHoveringRotationSuggestion;
+    private RotationLockController mRotationLockController;
+    private TaskStackListenerImpl mTaskStackListener;
+    private Consumer<Integer> mRotWatcherListener;
+    private boolean mIsNavigationBarShowing;
+
+    private final Runnable mRemoveRotationProposal =
+            () -> setRotateSuggestionButtonState(false /* visible */);
+    private final Runnable mCancelPendingRotationProposal =
+            () -> mPendingRotationSuggestion = false;
+    private Animator mRotateHideAnimator;
+    private boolean mAccessibilityFeedbackEnabled;
+
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+    private final ViewRippler mViewRippler = new ViewRippler();
+
+    private final Stub mRotationWatcher = new Stub() {
+        @Override
+        public void onRotationChanged(final int rotation) throws RemoteException {
+            // We need this to be scheduled as early as possible to beat the redrawing of
+            // window in response to the orientation change.
+            Handler h = getCurrentView().getHandler();
+            Message msg = Message.obtain(h, () -> {
+                // If the screen rotation changes while locked, potentially update lock to flow with
+                // new screen rotation and hide any showing suggestions.
+                if (mRotationLockController.isRotationLocked()) {
+                    if (shouldOverrideUserLockPrefs(rotation)) {
+                        setRotationLockedAtAngle(rotation);
+                    }
+                    setRotateSuggestionButtonState(false /* visible */, true /* forced */);
+                }
+
+                if (mRotWatcherListener != null) {
+                    mRotWatcherListener.accept(rotation);
+                }
+            });
+            msg.setAsynchronous(true);
+            h.sendMessageAtFrontOfQueue(msg);
+        }
+    };
+
+    /**
+     * Determines if rotation suggestions disabled2 flag exists in flag
+     * @param disable2Flags see if rotation suggestion flag exists in this flag
+     * @return whether flag exists
+     */
+    static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
+        return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
     }
 
-    public void setStyle(@StyleRes int styleRes) {
-        mStyleRes = styleRes;
+    public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId,
+            @NonNull Context context, @StyleRes int style) {
+        super(buttonResId, iconResId);
+
+        mStyleRes = style;
+        mIsNavigationBarShowing = true;
+        mRotationLockController = Dependency.get(RotationLockController.class);
+
+        // Register the task stack listener
+        mTaskStackListener = new TaskStackListenerImpl();
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+        setOnClickListener(this::onRotateSuggestionClick);
+        setOnHoverListener(this::onRotateSuggestionHover);
+
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                    .watchRotation(mRotationWatcher, context.getDisplay().getDisplayId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    public void addRotationCallback(Consumer<Integer> watcher) {
+        mRotWatcherListener = watcher;
+    }
+
+    public void setRotateSuggestionButtonState(boolean visible) {
+        setRotateSuggestionButtonState(visible, false /* force */);
+    }
+
+    public void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
+        // At any point the the button can become invisible because an a11y service became active.
+        // Similarly, a call to make the button visible may be rejected because an a11y service is
+        // active. Must account for this.
+        // Rerun a show animation to indicate change but don't rerun a hide animation
+        if (!visible && !isVisible()) return;
+
+        final View view = getCurrentView();
+        if (view == null) return;
+
+        final KeyButtonDrawable currentDrawable = getImageDrawable();
+        if (currentDrawable == null) return;
+
+        // Clear any pending suggestion flag as it has either been nullified or is being shown
+        mPendingRotationSuggestion = false;
+        view.removeCallbacks(mCancelPendingRotationProposal);
+
+        // Handle the visibility change and animation
+        if (visible) { // Appear and change (cannot force)
+            // Stop and clear any currently running hide animations
+            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+                mRotateHideAnimator.cancel();
+            }
+            mRotateHideAnimator = null;
+
+            // Reset the alpha if any has changed due to hide animation
+            view.setAlpha(1f);
+
+            // Run the rotate icon's animation if it has one
+            if (currentDrawable.canAnimate()) {
+                currentDrawable.resetAnimation();
+                currentDrawable.startAnimation();
+            }
+
+            if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
+
+            // Set visibility unless a11y service is active.
+            show();
+        } else { // Hide
+            mViewRippler.stop(); // Prevent any pending ripples, force hide or not
+
+            if (force) {
+                // If a hide animator is running stop it and make invisible
+                if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+                    mRotateHideAnimator.pause();
+                }
+                hide();
+                return;
+            }
+
+            // Don't start any new hide animations if one is running
+            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
+
+            ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f);
+            fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
+            fadeOut.setInterpolator(Interpolators.LINEAR);
+            fadeOut.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    hide();
+                }
+            });
+
+            mRotateHideAnimator = fadeOut;
+            fadeOut.start();
+        }
+    }
+
+    public void setAccessibilityFeedbackEnabled(boolean flag) {
+        mAccessibilityFeedbackEnabled = flag;
+    }
+
+    public void setRotationLockedAtAngle(int rotationSuggestion) {
+        mRotationLockController.setRotationLockedAtAngle(true /* locked */, rotationSuggestion);
+    }
+
+    public boolean isRotationLocked() {
+        return mRotationLockController.isRotationLocked();
+    }
+
+    public void onRotationProposal(int rotation, int windowRotation, boolean isValid) {
+        // This method will be called on rotation suggestion changes even if the proposed rotation
+        // is not valid for the top app. Use invalid rotation choices as a signal to remove the
+        // rotate button if shown.
+        if (!isValid) {
+            setRotateSuggestionButtonState(false /* visible */);
+            return;
+        }
+
+        // If window rotation matches suggested rotation, remove any current suggestions
+        if (rotation == windowRotation) {
+            getCurrentView().removeCallbacks(mRemoveRotationProposal);
+            setRotateSuggestionButtonState(false /* visible */);
+            return;
+        }
+
+        // Prepare to show the navbar icon by updating the icon style to change anim params
+        mLastRotationSuggestion = rotation; // Remember rotation for click
+        final boolean rotationCCW = isRotationAnimationCCW(windowRotation, rotation);
+        int style;
+        if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) {
+            style = rotationCCW ? R.style.RotateButtonCCWStart90 : R.style.RotateButtonCWStart90;
+        } else { // 90 or 270
+            style = rotationCCW ? R.style.RotateButtonCCWStart0 : R.style.RotateButtonCWStart0;
+        }
+        mStyleRes = style;
+        updateIcon();
+
+        if (mIsNavigationBarShowing) {
+            // The navbar is visible so show the icon right away
+            showAndLogRotationSuggestion();
+        } else {
+            // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
+            // visible given some time limit.
+            mPendingRotationSuggestion = true;
+            getCurrentView().removeCallbacks(mCancelPendingRotationProposal);
+            getCurrentView().postDelayed(mCancelPendingRotationProposal,
+                    NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
+        }
+    }
+
+    public void onDisable2FlagChanged(int state2) {
+        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
+        if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
+    }
+
+    public void onNavigationBarWindowVisibilityChange(boolean showing) {
+        if (mIsNavigationBarShowing != showing) {
+            mIsNavigationBarShowing = showing;
+
+            // If the navbar is visible, show the rotate button if there's a pending suggestion
+            if (showing && mPendingRotationSuggestion) {
+                showAndLogRotationSuggestion();
+            }
+        }
     }
 
     @Override
@@ -58,4 +298,168 @@
         Context context = new ContextThemeWrapper(getContext().getApplicationContext(), mStyleRes);
         return KeyButtonDrawable.create(context, mIconResId, false /* shadow */);
     }
+
+    @Override
+    public void onDestroy() {
+        // Unregister the task stack listener
+        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+
+        try {
+            WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private void onRotateSuggestionClick(View v) {
+        mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
+        incrementNumAcceptedRotationSuggestionsIfNeeded();
+        setRotationLockedAtAngle(mLastRotationSuggestion);
+    }
+
+    private boolean onRotateSuggestionHover(View v, MotionEvent event) {
+        final int action = event.getActionMasked();
+        mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
+                || (action == MotionEvent.ACTION_HOVER_MOVE);
+        rescheduleRotationTimeout(true /* reasonHover */);
+        return false; // Must return false so a11y hover events are dispatched correctly.
+    }
+
+    private void onRotationSuggestionsDisabled() {
+        // Immediately hide the rotate button and clear any planned removal
+        setRotateSuggestionButtonState(false /* visible */, true /* force */);
+        getCurrentView().removeCallbacks(mRemoveRotationProposal);
+    }
+
+    private void showAndLogRotationSuggestion() {
+        setRotateSuggestionButtonState(true /* visible */);
+        rescheduleRotationTimeout(false /* reasonHover */);
+        mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
+    }
+
+    private boolean shouldOverrideUserLockPrefs(final int rotation) {
+        // Only override user prefs when returning to the natural rotation (normally portrait).
+        // Don't let apps that force landscape or 180 alter user lock.
+        return rotation == NATURAL_ROTATION;
+    }
+
+    private boolean isRotationAnimationCCW(int from, int to) {
+        // All 180deg WM rotation animations are CCW, match that
+        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false;
+        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW
+        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true;
+        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true;
+        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false;
+        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW
+        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW
+        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true;
+        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false;
+        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false;
+        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW
+        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true;
+        return false; // Default
+    }
+
+    private void rescheduleRotationTimeout(final boolean reasonHover) {
+        // May be called due to a new rotation proposal or a change in hover state
+        if (reasonHover) {
+            // Don't reschedule if a hide animator is running
+            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
+            // Don't reschedule if not visible
+            if (!isVisible()) return;
+        }
+
+        // Stop any pending removal
+        getCurrentView().removeCallbacks(mRemoveRotationProposal);
+        // Schedule timeout
+        getCurrentView().postDelayed(mRemoveRotationProposal, computeRotationProposalTimeout());
+    }
+
+    private int computeRotationProposalTimeout() {
+        if (mAccessibilityFeedbackEnabled) return 20000;
+        if (mHoveringRotationSuggestion) return 16000;
+        return 10000;
+    }
+
+    private boolean isRotateSuggestionIntroduced() {
+        ContentResolver cr = getContext().getContentResolver();
+        return Settings.Secure.getInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0)
+                >= NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION;
+    }
+
+    private void incrementNumAcceptedRotationSuggestionsIfNeeded() {
+        // Get the number of accepted suggestions
+        ContentResolver cr = getContext().getContentResolver();
+        final int numSuggestions = Settings.Secure.getInt(cr,
+                Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0);
+
+        // Increment the number of accepted suggestions only if it would change intro mode
+        if (numSuggestions < NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION) {
+            Settings.Secure.putInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
+                    numSuggestions + 1);
+        }
+    }
+
+    private class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
+        // Invalidate any rotation suggestion on task change or activity orientation change
+        // Note: all callbacks happen on main thread
+
+        @Override
+        public void onTaskStackChanged() {
+            setRotateSuggestionButtonState(false /* visible */);
+        }
+
+        @Override
+        public void onTaskRemoved(int taskId) {
+            setRotateSuggestionButtonState(false /* visible */);
+        }
+
+        @Override
+        public void onTaskMovedToFront(int taskId) {
+            setRotateSuggestionButtonState(false /* visible */);
+        }
+
+        @Override
+        public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
+            // Only hide the icon if the top task changes its requestedOrientation
+            // Launcher can alter its requestedOrientation while it's not on top, don't hide on this
+            Optional.ofNullable(ActivityManagerWrapper.getInstance())
+                    .map(ActivityManagerWrapper::getRunningTask)
+                    .ifPresent(a -> {
+                        if (a.id == taskId) setRotateSuggestionButtonState(false /* visible */);
+                    });
+        }
+    }
+
+    private class ViewRippler {
+        private static final int RIPPLE_OFFSET_MS = 50;
+        private static final int RIPPLE_INTERVAL_MS = 2000;
+        private View mRoot;
+
+        public void start(View root) {
+            stop(); // Stop any pending ripple animations
+
+            mRoot = root;
+
+            // Schedule pending ripples, offset the 1st to avoid problems with visibility change
+            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
+            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 2 * RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 3 * RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 4 * RIPPLE_INTERVAL_MS);
+        }
+
+        public void stop() {
+            if (mRoot != null) mRoot.removeCallbacks(mRipple);
+        }
+
+        private final Runnable mRipple = new Runnable() {
+            @Override
+            public void run() { // Cause the ripple to fire via false presses
+                if (!mRoot.isAttachedToWindow()) return;
+                mRoot.setPressed(true /* pressed */);
+                mRoot.setPressed(false /* pressed */);
+            }
+        };
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
new file mode 100644
index 0000000..e546119
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import android.view.View;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+
+/**
+ * {@link ShadeController} is an abstraction of the work that used to be hard-coded in
+ * {@link StatusBar}. The shade itself represents the concept of the status bar window state, and
+ * can be in multiple states: dozing, locked, showing the bouncer, occluded, etc. All/some of these
+ * are coordinated with {@link StatusBarKeyguardViewManager} via
+ * {@link com.android.systemui.keyguard.KeyguardViewMediator} and others.
+ */
+public interface ShadeController {
+
+    /**
+     * Shows the keyguard bouncer - the password challenge on the lock screen
+     *
+     * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
+     * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
+     */
+    void showBouncer(boolean scrimmed);
+
+    /**
+     * Make our window larger and the panel expanded
+     */
+    void instantExpandNotificationsPanel();
+
+    /**
+     * If the notifications panel is not fully expanded, collapse it animated.
+     *
+     * @return Seems to always return false
+     */
+    boolean closeShadeIfOpen();
+
+    /**
+     * Add a runnable for NotificationPanelView to post when the panel is expanded.
+     *
+     * @param action the action to post
+     */
+    void postOnShadeExpanded(Runnable action);
+
+    /**
+     * Add a runnable to be executed after the shade collapses. Post-collapse runnables are
+     * aggregated and run serially.
+     *
+     * @param action the action to execute
+     */
+    void addPostCollapseAction(Runnable action);
+
+    /**
+     * Ask shade controller to set the state to {@link StatusBarState#KEYGUARD}, but only from
+     * {@link StatusBarState#SHADE_LOCKED}
+     */
+    void goToKeyguard();
+
+    /**
+     * When the keyguard is showing and covered by something (bouncer, keyguard activity, etc.) it
+     * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
+     *
+     * @return whether the keyguard is currently occluded
+     */
+    boolean isOccluded();
+
+    /**
+     * Notify the shade controller that the current user changed
+     *
+     * @param newUserId userId of the new user
+     */
+    void setLockscreenUser(int newUserId);
+
+    /**
+     * Dozing is when the screen is in AOD or asleep
+     *
+     * @return true if we are dozing
+     */
+    boolean isDozing();
+
+    /**
+     * Ask the display to wake up if currently dozing, else do nothing
+     *
+     * @param time when to wake up
+     * @param view the view requesting the wakeup
+     */
+    void wakeUpIfDozing(long time, View view);
+
+    /**
+     * If secure with redaction: Show bouncer, go to unlocked shade.
+     *
+     * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
+     *
+     * @param startingChild The view to expand after going to the shade.
+     */
+    void goToLockedShade(View startingChild);
+
+    /**
+     * Adds a {@param runnable} to be executed after Keyguard is gone.
+     */
+    void addAfterKeyguardGoneRunnable(Runnable runnable);
+
+    /**
+     * Close the shade if it was open
+     *
+     * @return true if the shade was open, else false
+     */
+    boolean collapsePanel();
+
+    /**
+     * If {@param animate}, does the same as {@link #collapsePanel()}. Otherwise, instantly collapse
+     * the panel. Post collapse runnables will be executed
+     *
+     * @param animate
+     */
+    void collapsePanel(boolean animate);
+
+    /**
+     * Callback to tell the shade controller that an activity launch animation was canceled
+     */
+    void onLaunchAnimationCancelled();
+
+    /**
+     * When notifications update, give the shade controller a chance to do thing in response to
+     * the new data set
+     */
+    void updateAreThereNotifications();
+
+    /**
+     * Callback to notify the shade controller that a {@link ActivatableNotificationView} has become
+     * inactive
+     */
+    void onActivationReset();
+
+}
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 56e5a1e..b9ca949 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -26,10 +26,8 @@
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
-import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
-import static com.android.systemui.statusbar.NotificationLockscreenUserManager
-        .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.NotificationMediaManager.DEBUG_MEDIA;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -54,7 +52,6 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
-import android.app.TaskStackBuilder;
 import android.app.UiModeManager;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
@@ -65,31 +62,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.IntentSender;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
 import android.media.AudioAttributes;
-import android.media.MediaMetadata;
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -105,14 +92,10 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
-import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
@@ -122,7 +105,6 @@
 import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -130,19 +112,15 @@
 import android.view.animation.AccelerateInterpolator;
 import android.widget.DateTimeView;
 import android.widget.ImageView;
-import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.MessagingGroup;
 import com.android.internal.widget.MessagingMessage;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
@@ -152,11 +130,11 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.InitController;
 import com.android.systemui.Interpolators;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
@@ -185,38 +163,34 @@
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.WindowManagerProxy;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
-import com.android.systemui.statusbar.notification.AppOpsListener;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.KeyboardShortcuts;
 import com.android.systemui.statusbar.KeyguardIndicationController;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.NotificationInfo;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
-import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.AppOpsListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
@@ -230,7 +204,6 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
@@ -253,9 +226,9 @@
 public class StatusBar extends SystemUI implements DemoMode,
         ActivityStarter, OnUnlockMethodChangedListener,
         OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
-        ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter,
-        StatusBarStateController.StateListener,  AmbientPulseManager.OnAmbientChangedListener,
-        ActivityLaunchAnimator.Callback {
+        ColorExtractor.OnColorsChangedListener, ConfigurationListener,
+        StatusBarStateController.StateListener, ShadeController,
+        ActivityLaunchAnimator.Callback, AmbientPulseManager.OnAmbientChangedListener {
     public static final boolean MULTIUSER_DEBUG = false;
 
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -324,10 +297,10 @@
 
     /** If true, the system is in the half-boot-to-decryption-screen state.
      * Prudently disable QS and notifications.  */
-    private static final boolean ONLY_CORE_APPS;
+    public static final boolean ONLY_CORE_APPS;
 
     /** If true, the lockscreen will show a distinct wallpaper */
-    private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
+    public static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
 
     static {
         boolean onlyCoreApps;
@@ -376,7 +349,6 @@
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
-    private TextView mNotificationPanelDebugText;
 
     // settings
     private QSPanel mQSPanel;
@@ -385,15 +357,12 @@
 
     // RemoteInputView to be activated after unlock
     private View mPendingRemoteInputView;
-    private View mPendingWorkRemoteInputView;
 
     private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
             Dependency.get(RemoteInputQuickSettingsDisabler.class);
 
     private View mReportRejectedTouch;
 
-    private int mMaxAllowedKeyguardNotifications;
-
     private boolean mExpandedVisible;
 
     private final int[] mAbsPos = new int[2];
@@ -460,7 +429,6 @@
     private int mInteractingWindows;
     private boolean mAutohideSuspended;
     private int mStatusBarMode;
-    private int mMaxKeyguardNotifications;
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
     protected ScrimController mScrimController;
@@ -479,9 +447,6 @@
 
     protected BackDropView mBackdrop;
     protected ImageView mBackdropFront, mBackdropBack;
-    protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
-    protected final PorterDuffXfermode mSrcOverXferMode =
-            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
 
     private NotificationMediaManager mMediaManager;
     protected NotificationLockscreenUserManager mLockscreenUserManager;
@@ -524,7 +489,6 @@
     private boolean mIsOccluded;
     private boolean mWereIconsJustHidden;
     private boolean mBouncerWasShowingWhenHidden;
-    private boolean mIsCollapsingToShowActivityOverLockscreen;
 
     // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
     // this animation is tied to the scrim for historic reasons.
@@ -557,13 +521,9 @@
     private BatteryController mBatteryController;
     protected boolean mPanelExpanded;
     private UiModeManager mUiModeManager;
-    private boolean mKeyguardRequested;
     private boolean mIsKeyguard;
     private LogMaker mStatusBarStateLog;
-    private final LockscreenGestureLogger mLockscreenGestureLogger =
-            Dependency.get(LockscreenGestureLogger.class);
     protected NotificationIconAreaController mNotificationIconAreaController;
-    private boolean mReinflateNotificationsOnUserSwitched;
     @Nullable private View mAmbientIndicationContainer;
     private SysuiColorExtractor mColorExtractor;
     private ScreenLifecycle mScreenLifecycle;
@@ -598,10 +558,10 @@
 
     private NavigationBarFragment mNavigationBar;
     private View mNavigationBarView;
-    protected ActivityLaunchAnimator mActivityLaunchAnimator;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private boolean mVibrateOnOpening;
     private VibratorHelper mVibratorHelper;
+    protected NotificationPresenter mPresenter;
 
     @Override
     public void start() {
@@ -626,11 +586,11 @@
         mEntryManager = Dependency.get(NotificationEntryManager.class);
         mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
         mAppOpsListener = Dependency.get(AppOpsListener.class);
-        mAppOpsListener.setUpWithPresenter(this, mEntryManager);
         mZenController = Dependency.get(ZenModeController.class);
         mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
-
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+
         mColorExtractor.addOnColorsChangedListener(this);
         mStatusBarStateController.addListener(this, StatusBarStateController.RANK_STATUS_BAR);
 
@@ -659,17 +619,12 @@
 
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
-        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
-
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
         mRecents = getComponent(Recents.class);
 
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mLockPatternUtils = new LockPatternUtils(mContext);
-
-        mMediaManager.setUpWithPresenter(this, mEntryManager);
 
         // Connect in to the status bar manager service
         mCommandQueue = getComponent(CommandQueue.class);
@@ -696,8 +651,9 @@
                 wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
         mWallpaperChangedReceiver.onReceive(mContext, null);
 
-        mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
-        mCommandQueue.disable(switches[0], switches[6], false /* animate */);
+        // Set up the initial notification state. This needs to happen before CommandQueue.disable()
+        setUpPresenter();
+
         setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
                 fullscreenStackBounds, dockedStackBounds);
         topAppWindowChanged(switches[2] != 0);
@@ -710,8 +666,6 @@
             mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
         }
 
-        // Set up the initial notification state.
-        mNotificationListener.setUpWithPresenter(this, mEntryManager);
 
         if (DEBUG) {
             Log.d(TAG, String.format(
@@ -724,24 +678,12 @@
                    ));
         }
 
-        setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());
-
         IntentFilter internalFilter = new IntentFilter();
         internalFilter.addAction(BANNER_ACTION_CANCEL);
         internalFilter.addAction(BANNER_ACTION_SETUP);
         mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
                 null);
 
-        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
-                Context.VR_SERVICE));
-        if (vrManager != null) {
-            try {
-                vrManager.registerListener(mVrStateCallbacks);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
-            }
-        }
-
         IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
         try {
@@ -769,6 +711,13 @@
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
 
         Dependency.get(ConfigurationController.class).addCallback(this);
+
+        // set the initial view visibility
+        Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications);
+        Dependency.get(InitController.class).addPostInitTask(() -> {
+            setUpDisableFlags(switches[0], switches[6]);
+        });
+
     }
 
     // ================================================================================
@@ -788,24 +737,9 @@
         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
         mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
         mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
-        NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller;
         mZenController.addCallback(this);
-        mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
-                this,
-                mNotificationPanel,
-                notifListContainer);
-        mGutsManager.setUpWithPresenter(this, notifListContainer, mCheckSaveListener,
-                key -> {
-                    try {
-                        mBarService.onNotificationSettingsViewed(key);
-                    } catch (RemoteException e) {
-                        // if we're here we're dead
-                    }
-                });
-        mNotificationLogger.setUpWithEntryManager(mEntryManager, notifListContainer);
-        mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
-        mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
-                R.id.notification_container_parent));
+        NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller;
+        mNotificationLogger.setUpWithContainer(notifListContainer);
 
         mNotificationIconAreaController = SystemUIFactory.getInstance()
                 .createNotificationIconAreaController(context, this);
@@ -850,7 +784,7 @@
                             mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
                     mHeadsUpAppearanceController.readFrom(oldController);
                     mStatusBarWindow.setStatusBarView(mStatusBarView);
-                    setAreThereNotifications();
+                    updateAreThereNotifications();
                     checkBarModes();
                 }).getFragmentManager()
                 .beginTransaction()
@@ -872,13 +806,6 @@
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
         putComponent(HeadsUpManager.class, mHeadsUpManager);
 
-        mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager);
-        mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, notifListContainer);
-
-        if (MULTIUSER_DEBUG) {
-            mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
-            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
-        }
 
         try {
             boolean showNav = mWindowManagerService.hasNavigationBar();
@@ -890,10 +817,6 @@
             // no window manager? good luck with that
         }
 
-        mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
-        mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
-        mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
-
         if (ENABLE_LOCKSCREEN_WALLPAPER) {
             mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
         }
@@ -908,9 +831,6 @@
         mAmbientIndicationContainer = mStatusBarWindow.findViewById(
                 R.id.ambient_indication_container);
 
-        // set the initial view visibility
-        setAreThereNotifications();
-
         // TODO: Find better place for this callback.
         mBatteryController.addCallback(new BatteryStateChangeCallback() {
             @Override
@@ -948,6 +868,12 @@
         mDozeScrimController = new DozeScrimController(mScrimController, context,
                 DozeParameters.getInstance(context));
 
+        mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
+        mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
+        mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
+        mMediaManager.setup(mBackdrop, mBackdropFront, mBackdropBack,
+                mScrimController, mLockscreenWallpaper);
+
         // Other icons
         mVolumeComponent = getComponent(VolumeComponent.class);
 
@@ -1053,6 +979,50 @@
         ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
     }
 
+    protected void setUpPresenter() {
+        // Set up the initial notification state.
+        mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
+                mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
+                mScrimController, this);
+        mAppOpsListener.setUpWithPresenter(mPresenter);
+        mNotificationListener.setUpWithPresenter(mPresenter);
+        mNotificationShelf.setOnActivatedListener(mPresenter);
+        mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
+    }
+
+    /**
+     * Post-init task of {@link #start()}
+     * @param state1 disable1 flags
+     * @param state2 disable2 flags
+     */
+    protected void setUpDisableFlags(int state1, int state2) {
+        mCommandQueue.disable(state1, state2, false /* animate */);
+    }
+
+    @Override
+    public void addAfterKeyguardGoneRunnable(Runnable runnable) {
+        mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
+    }
+
+    @Override
+    public boolean isDozing() {
+        return mDozing && mNotificationPanel.isFullyDark();
+    }
+
+    @Override
+    public void wakeUpIfDozing(long time, View where) {
+        if (mDozing) {
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            pm.wakeUp(time, "com.android.systemui:NODOZE");
+            mWakeUpComingFromTouch = true;
+            where.getLocationInWindow(mTmpInt2);
+            mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
+                    mTmpInt2[1] + where.getHeight() / 2);
+            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+            mFalsingManager.onScreenOnFromTouch();
+        }
+    }
+
     protected void createNavigationBar() {
         mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
             mNavigationBar = (NavigationBarFragment) fragment;
@@ -1084,7 +1054,6 @@
         mNotificationShelf =
                 (NotificationShelf) LayoutInflater.from(mContext).inflate(
                         R.layout.status_bar_notification_shelf, mStackScroller, false);
-        mNotificationShelf.setOnActivatedListener(this);
         mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
     }
 
@@ -1092,13 +1061,6 @@
     public void onDensityOrFontScaleChanged() {
         MessagingMessage.dropCache();
         MessagingGroup.dropCache();
-        // start old BaseStatusBar.onDensityOrFontScaleChanged().
-        if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
-            mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
-        } else {
-            mReinflateNotificationsOnUserSwitched = true;
-        }
-        // end old BaseStatusBar.onDensityOrFontScaleChanged().
         // TODO: Remove this.
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.onDensityOrFontScaleChanged();
@@ -1169,8 +1131,6 @@
                 mScrimController, this, UnlockMethodCache.getInstance(mContext));
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController);
-        //TODO: Can we put the keyguard view manager in Dependency?
-        mLockscreenUserManager.setKeyguardViewManager(mStatusBarKeyguardViewManager);
         mKeyguardIndicationController
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -1178,6 +1138,7 @@
 
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
+        mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
         Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
         Trace.endSection();
     }
@@ -1234,73 +1195,13 @@
         return true;
     }
 
-    @Override
-    public void onPerformRemoveNotification(StatusBarNotification n) {
-        if (mNotificationPanel.hasPulsingNotifications() &&
-                    !mAmbientPulseManager.hasNotifications()) {
-            // We were showing a pulse for a notification, but no notifications are pulsing anymore.
-            // Finish the pulse.
-            mDozeScrimController.pulseOutNow();
-        }
-    }
-
-    @Override
-    public void updateNotificationViews() {
-        // The function updateRowStates depends on both of these being non-null, so check them here.
-        // We may be called before they are set from DeviceProvisionedController's callback.
-        if (mScrimController == null) return;
-
-        // Do not modify the notifications during collapse.
-        if (isCollapsing()) {
-            addPostCollapseAction(this::updateNotificationViews);
-            return;
-        }
-
-        mViewHierarchyManager.updateNotificationViews();
-
-        mNotificationPanel.updateNotificationViews();
-
-        updateQsExpansionEnabled();
-
-        // Let's also update the icons
-        mNotificationIconAreaController.updateNotificationIcons();
-    }
-
-    @Override
-    public void onNotificationAdded(Entry shadeEntry) {
-        // Recalculate the position of the sliding windows and the titles.
-        setAreThereNotifications();
-    }
-
-    @Override
-    public void onNotificationUpdated(StatusBarNotification notification) {
-        setAreThereNotifications();
-    }
-
-    @Override
-    public void onNotificationRemoved(String key, StatusBarNotification old) {
-        if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
-
-        if (old != null) {
-            if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
-                    && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
-                if (mState == StatusBarState.SHADE) {
-                    animateCollapsePanels();
-                } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
-                    goToKeyguard();
-                }
-            }
-        }
-        setAreThereNotifications();
-    }
-
     /**
      * Disable QS if device not provisioned.
      * If the user switcher is simple then disable QS during setup because
      * the user intends to use the lock screen user switcher, QS in not needed.
      */
     private void updateQsExpansionEnabled() {
-        mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
+        mNotificationPanel.setQsExpansionEnabled(mDeviceProvisionedController.isDeviceProvisioned()
                 && (mUserSetup || mUserSwitcherController == null
                         || !mUserSwitcherController.isSimpleUserSwitcher())
                 && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
@@ -1337,12 +1238,11 @@
         mEntryManager.updateNotifications();
     }
 
-    protected void setAreThereNotifications() {
-
+    public void updateAreThereNotifications() {
         if (SPEW) {
             final boolean clearable = hasActiveNotifications() &&
                     mNotificationPanel.hasActiveClearableNotifications();
-            Log.d(TAG, "setAreThereNotifications: N=" +
+            Log.d(TAG, "updateAreThereNotifications: N=" +
                     mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" +
                     hasActiveNotifications() + " clearable=" + clearable);
         }
@@ -1368,192 +1268,9 @@
                         .start();
             }
         }
-
         mMediaManager.findAndUpdateMediaNotifications();
     }
 
-
-    /**
-     * Hide the album artwork that is fading out and release its bitmap.
-     */
-    protected final Runnable mHideBackdropFront = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG_MEDIA) {
-                Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
-            }
-            mBackdropFront.setVisibility(View.INVISIBLE);
-            mBackdropFront.animate().cancel();
-            mBackdropFront.setImageDrawable(null);
-        }
-    };
-
-    // TODO: Move this to NotificationMediaManager.
-    /**
-     * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
-     */
-    @Override
-    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
-        Trace.beginSection("StatusBar#updateMediaMetaData");
-        if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
-            Trace.endSection();
-            return;
-        }
-
-        if (mBackdrop == null) {
-            Trace.endSection();
-            return; // called too early
-        }
-
-        boolean wakeAndUnlock = mBiometricUnlockController != null
-            && mBiometricUnlockController.isWakeAndUnlock();
-        if (mLaunchTransitionFadingAway || wakeAndUnlock) {
-            mBackdrop.setVisibility(View.INVISIBLE);
-            Trace.endSection();
-            return;
-        }
-
-        MediaMetadata mediaMetadata = mMediaManager.getMediaMetadata();
-
-        if (DEBUG_MEDIA) {
-            Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
-                    + mMediaManager.getMediaNotificationKey()
-                    + " metadata=" + mediaMetadata
-                    + " metaDataChanged=" + metaDataChanged
-                    + " state=" + mState);
-        }
-
-        Drawable artworkDrawable = null;
-        if (mediaMetadata != null) {
-            Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
-            if (artworkBitmap == null) {
-                artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
-                // might still be null
-            }
-            if (artworkBitmap != null) {
-                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
-            }
-        }
-        boolean allowWhenShade = false;
-        if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
-            Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
-            if (lockWallpaper != null) {
-                artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
-                        mBackdropBack.getResources(), lockWallpaper);
-                // We're in the SHADE mode on the SIM screen - yet we still need to show
-                // the lockscreen wallpaper in that mode.
-                allowWhenShade = mStatusBarKeyguardViewManager != null
-                        && mStatusBarKeyguardViewManager.isShowing();
-            }
-        }
-
-        boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
-                && mStatusBarKeyguardViewManager.isOccluded();
-
-        final boolean hasArtwork = artworkDrawable != null;
-        mColorExtractor.setHasBackdrop(hasArtwork);
-        if (mScrimController != null) {
-            mScrimController.setHasBackdrop(hasArtwork);
-        }
-
-        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
-                && (mState != StatusBarState.SHADE || allowWhenShade)
-                && mBiometricUnlockController.getMode()
-                        != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                && !hideBecauseOccluded) {
-            // time to show some art!
-            if (mBackdrop.getVisibility() != View.VISIBLE) {
-                mBackdrop.setVisibility(View.VISIBLE);
-                if (allowEnterAnimation) {
-                    mBackdrop.setAlpha(0);
-                    mBackdrop.animate().alpha(1f);
-                } else {
-                    mBackdrop.animate().cancel();
-                    mBackdrop.setAlpha(1f);
-                }
-                mStatusBarWindowController.setBackdropShowing(true);
-                metaDataChanged = true;
-                if (DEBUG_MEDIA) {
-                    Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
-                }
-            }
-            if (metaDataChanged) {
-                if (mBackdropBack.getDrawable() != null) {
-                    Drawable drawable =
-                            mBackdropBack.getDrawable().getConstantState()
-                                    .newDrawable(mBackdropFront.getResources()).mutate();
-                    mBackdropFront.setImageDrawable(drawable);
-                    mBackdropFront.setAlpha(1f);
-                    mBackdropFront.setVisibility(View.VISIBLE);
-                } else {
-                    mBackdropFront.setVisibility(View.INVISIBLE);
-                }
-
-                if (DEBUG_MEDIA_FAKE_ARTWORK) {
-                    final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
-                    Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
-                    mBackdropBack.setBackgroundColor(0xFFFFFFFF);
-                    mBackdropBack.setImageDrawable(new ColorDrawable(c));
-                } else {
-                    mBackdropBack.setImageDrawable(artworkDrawable);
-                }
-
-                if (mBackdropFront.getVisibility() == View.VISIBLE) {
-                    if (DEBUG_MEDIA) {
-                        Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
-                                + mBackdropFront.getDrawable()
-                                + " to "
-                                + mBackdropBack.getDrawable());
-                    }
-                    mBackdropFront.animate()
-                            .setDuration(250)
-                            .alpha(0f).withEndAction(mHideBackdropFront);
-                }
-            }
-        } else {
-            // need to hide the album art, either because we are unlocked, on AOD
-            // or because the metadata isn't there to support it
-            if (mBackdrop.getVisibility() != View.GONE) {
-                if (DEBUG_MEDIA) {
-                    Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
-                }
-                boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
-                if (mBiometricUnlockController.getMode()
-                        == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                        || hideBecauseOccluded || cannotAnimateDoze) {
-
-                    // We are unlocking directly - no animation!
-                    mBackdrop.setVisibility(View.GONE);
-                    mBackdropBack.setImageDrawable(null);
-                    mStatusBarWindowController.setBackdropShowing(false);
-                } else {
-                    mStatusBarWindowController.setBackdropShowing(false);
-                    mBackdrop.animate()
-                            .alpha(0)
-                            .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
-                            .setDuration(300)
-                            .setStartDelay(0)
-                            .withEndAction(() -> {
-                                mBackdrop.setVisibility(View.GONE);
-                                mBackdropFront.animate().cancel();
-                                mBackdropBack.setImageDrawable(null);
-                                mHandler.post(mHideBackdropFront);
-                            });
-                    if (mKeyguardMonitor.isKeyguardFadingAway()) {
-                        mBackdrop.animate()
-                                // Make it disappear faster, as the focus should be on the activity
-                                // behind.
-                                .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
-                                .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
-                                .setInterpolator(Interpolators.LINEAR)
-                                .start();
-                    }
-                }
-            }
-        }
-        Trace.endSection();
-    }
-
     private void updateReportRejectedTouchVisibility() {
         if (mReportRejectedTouch == null) {
             return;
@@ -1646,15 +1363,6 @@
         }
     }
 
-    /**
-     * Reapplies the disable flags as last requested by StatusBarManager.
-     *
-     * This needs to be called if state used by adjustDisableFlags changes.
-     */
-    public void recomputeDisableFlags(boolean animate) {
-        mCommandQueue.recomputeDisableFlags(animate);
-    }
-
     protected H createHandler() {
         return new StatusBar.H();
     }
@@ -1695,53 +1403,6 @@
         return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
     }
 
-    @Override
-    public boolean isDozing() {
-        return mDozing && mNotificationPanel.isFullyDark();
-    }
-
-    @Override
-    public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
-        if (isDozing()) {
-            return false;
-        }
-
-        if (mIsOccluded) {
-            boolean devicePublic = mLockscreenUserManager.
-                    isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
-            boolean userPublic = devicePublic
-                    || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
-            boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
-            if (userPublic && needsRedaction) {
-                return false;
-            }
-        }
-
-        if (!panelsEnabled()) {
-            if (DEBUG) {
-                Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
-            }
-            return false;
-        }
-
-        if (sbn.getNotification().fullScreenIntent != null) {
-            if (mAccessibilityManager.isTouchExplorationEnabled()) {
-                if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
-                return false;
-            } else {
-                // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
-                return !mStatusBarKeyguardViewManager.isShowing()
-                        || mStatusBarKeyguardViewManager.isOccluded();
-            }
-        }
-        return true;
-    }
-
-    @Override  // NotificationData.Environment
-    public String getCurrentMediaNotificationKey() {
-        return mMediaManager.getMediaNotificationKey();
-    }
-
     /**
      * To be called when there's a state change in StatusBarKeyguardViewManager.
      */
@@ -1815,12 +1476,6 @@
         }
     }
 
-    protected void setHeadsUpUser(int newUserId) {
-        if (mHeadsUpManager != null) {
-            mHeadsUpManager.setUser(newUserId);
-        }
-    }
-
     public boolean isKeyguardCurrentlySecure() {
         return !mUnlockMethodCache.canSkipBouncer();
     }
@@ -1868,6 +1523,11 @@
         return mAmbientIndicationContainer;
     }
 
+    @Override
+    public boolean isOccluded() {
+        return mIsOccluded;
+    }
+
     public void setOccluded(boolean occluded) {
         mIsOccluded = occluded;
         mScrimController.setKeyguardOccluded(occluded);
@@ -1901,10 +1561,10 @@
                 mWereIconsJustHidden = true;
                 mHandler.postDelayed(() -> {
                     mWereIconsJustHidden = false;
-                    recomputeDisableFlags(true);
+                    mCommandQueue.recomputeDisableFlags(true);
                 }, 500);
             } else {
-                recomputeDisableFlags(animate);
+                mCommandQueue.recomputeDisableFlags(animate);
             }
         }
         if (shouldHideIconsForBouncer) {
@@ -1912,20 +1572,21 @@
         }
     }
 
-    @Override
-    public void onLaunchAnimationCancelled() {
-        if (!isCollapsing()) {
-            onClosingFinished();
-        }
-    }
-
     public boolean isHeadsUpShouldBeVisible() {
         return mHeadsUpAppearanceController.shouldBeVisible();
     }
 
+    //TODO: These can / should probably be moved to NotificationPresenter or ShadeController
+    @Override
+    public void onLaunchAnimationCancelled() {
+        if (!mPresenter.isCollapsing()) {
+            onClosingFinished();
+        }
+    }
+
     @Override
     public void onExpandAnimationFinished(boolean launchIsFullScreen) {
-        if (!isCollapsing()) {
+        if (!mPresenter.isCollapsing()) {
             onClosingFinished();
         }
         if (launchIsFullScreen) {
@@ -1935,8 +1596,9 @@
 
     @Override
     public void onExpandAnimationTimedOut() {
-        if (isPresenterFullyCollapsed() && !isCollapsing()
-                && !mActivityLaunchAnimator.isLaunchForActivity()) {
+        ActivityLaunchAnimator animator = mPresenter.getActivityLaunchAnimator();
+        if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
+                && animator != null && !animator.isLaunchForActivity()) {
             onClosingFinished();
         } else {
             collapsePanel(true /* animate */);
@@ -1948,6 +1610,14 @@
         return mState == StatusBarState.SHADE;
     }
 
+    public boolean isDeviceInVrMode() {
+        return mPresenter.isDeviceInVrMode();
+    }
+
+    public NotificationPresenter getPresenter() {
+        return mPresenter;
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2005,7 +1675,7 @@
     @Override
     public void handleSystemKey(int key) {
         if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
-        if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
+        if (!mCommandQueue.panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
                 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
             return;
         }
@@ -2047,15 +1717,9 @@
         }
     }
 
-    boolean panelsEnabled() {
-        return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
-                && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
-                && !ONLY_CORE_APPS;
-    }
-
     void makeExpandedVisible(boolean force) {
         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (!force && (mExpandedVisible || !panelsEnabled())) {
+        if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
             return;
         }
 
@@ -2066,7 +1730,7 @@
         mStatusBarWindowController.setPanelVisible(true);
 
         visibilityChanged(true);
-        recomputeDisableFlags(!force /* animate */);
+        mCommandQueue.recomputeDisableFlags(!force /* animate */);
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
     }
 
@@ -2099,12 +1763,12 @@
         }
     }
 
-    @Override
     public void animateCollapsePanels(int flags) {
         animateCollapsePanels(flags, false /* force */, false /* delayed */,
                 1.0f /* speedUpFactor */);
     }
 
+    @Override
     public void animateCollapsePanels(int flags, boolean force) {
         animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
     }
@@ -2155,7 +1819,7 @@
     }
 
     public void dispatchNotificationsPanelTouchEvent(MotionEvent ev) {
-        if (!panelsEnabled()) {
+        if (!mCommandQueue.panelsEnabled()) {
             return;
         }
         mNotificationPanel.dispatchTouchEvent(ev);
@@ -2173,7 +1837,7 @@
     @Override
     public void animateExpandNotificationsPanel() {
         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
-        if (!panelsEnabled()) {
+        if (!mCommandQueue.panelsEnabled()) {
             return ;
         }
 
@@ -2185,7 +1849,7 @@
     @Override
     public void animateExpandSettingsPanel(@Nullable String subPanel) {
         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
-        if (!panelsEnabled()) {
+        if (!mCommandQueue.panelsEnabled()) {
             return;
         }
 
@@ -2233,12 +1897,13 @@
 
         runPostCollapseRunnables();
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-        if (!mIsCollapsingToShowActivityOverLockscreen) {
+        if (!mPresenter.isCollapsingToShowActivityOverLockscreen()) {
             showBouncerIfKeyguard();
         } else if (DEBUG) {
             Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
         }
-        recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
+        mCommandQueue.recomputeDisableFlags(
+                mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
 
         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
         // the bouncer appear animation.
@@ -2330,7 +1995,7 @@
 
             // update low profile
             if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
-                setAreThereNotifications();
+                updateAreThereNotifications();
             }
 
             // ready to unhide
@@ -2703,9 +2368,6 @@
     private void addStatusBarWindow() {
         makeStatusBarView();
         mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
-        mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
-                mNotificationPanel.createRemoteInputDelegate());
-        mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
         mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());
     }
 
@@ -2750,7 +2412,7 @@
     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
             final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
             final Callback callback, int flags) {
-        if (onlyProvisioned && !isDeviceProvisioned()) return;
+        if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return;
 
         final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
                 mContext, intent, mLockscreenUserManager.getCurrentUserId());
@@ -2888,7 +2550,7 @@
                 }
             } else if (ACTION_FAKE_ARTWORK.equals(action)) {
                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
-                    updateMediaMetaData(true, true);
+                    mPresenter.updateMediaMetaData(true, true);
                 }
             }
         }
@@ -2917,7 +2579,8 @@
         dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
     }
 
-    private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
+    @Override
+    public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
             boolean afterKeyguardGone) {
         if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
                 && mUnlockMethodCache.canSkipBouncer()
@@ -2951,38 +2614,10 @@
     }
 
     @Override
-    public void onUserSwitched(int newUserId) {
-        // Begin old BaseStatusBar.userSwitched
-        setHeadsUpUser(newUserId);
-        // End old BaseStatusBar.userSwitched
-        if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
-        animateCollapsePanels();
-        if (mReinflateNotificationsOnUserSwitched) {
-            mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
-            mReinflateNotificationsOnUserSwitched = false;
-        }
-        updateNotificationViews();
-        mMediaManager.clearCurrentMediaNotification();
-        setLockscreenUser(newUserId);
-        mWallpaperChangedReceiver.onReceive(mContext, null);
-    }
-
-    @Override
-    public NotificationLockscreenUserManager getNotificationLockscreenUserManager() {
-        return mLockscreenUserManager;
-    }
-
-    @Override
-    public void onBindRow(Entry entry, PackageManager pmUser,
-            StatusBarNotification sbn, ExpandableNotificationRow row) {
-        row.setAboveShelfChangedListener(mAboveShelfObserver);
-        row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
-    }
-
-    protected void setLockscreenUser(int newUserId) {
+    public void setLockscreenUser(int newUserId) {
         mLockscreenWallpaper.setCurrentUser(newUserId);
         mScrimController.setCurrentUser(newUserId);
-        updateMediaMetaData(true, false);
+        mWallpaperChangedReceiver.onReceive(mContext, null);
     }
 
     /**
@@ -3020,8 +2655,6 @@
         if (mStatusBarWindowController != null && mNaturalBarHeight != oldBarHeight) {
             mStatusBarWindowController.setBarHeight(mNaturalBarHeight);
         }
-        mMaxAllowedKeyguardNotifications = res.getInteger(
-                R.integer.keyguard_max_notification_count);
 
         if (DEBUG) Log.v(TAG, "defineSlots");
     }
@@ -3058,12 +2691,12 @@
         if (visibleToUser) {
             boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
             boolean clearNotificationEffects =
-                    !isPresenterFullyCollapsed() &&
+                    !mPresenter.isPresenterFullyCollapsed() &&
                             (mState == StatusBarState.SHADE
                                     || mState == StatusBarState.SHADE_LOCKED);
             int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
                     .size();
-            if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
+            if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
                 notificationLoad = 1;
             }
             final int finalNotificationLoad = notificationLoad;
@@ -3298,13 +2931,8 @@
         }
     }
 
-    @Override
-    public boolean isPresenterFullyCollapsed() {
-        return mNotificationPanel.isFullyCollapsed();
-    }
-
     public void showKeyguard() {
-        mKeyguardRequested = true;
+        mStatusBarStateController.setKeyguardRequested(true);
         mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
         mPendingRemoteInputView = null;
         updateIsKeyguard();
@@ -3312,11 +2940,12 @@
     }
 
     public boolean hideKeyguard() {
-        mKeyguardRequested = false;
+        mStatusBarStateController.setKeyguardRequested(false);
         return updateIsKeyguard();
     }
 
     /**
+     * stop(tag)
      * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
      */
     public boolean isFullScreenUserSwitcherState() {
@@ -3333,7 +2962,8 @@
         // turned off fully.
         boolean keyguardForDozing = mDozingRequested &&
                 (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
-        boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking;
+        boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
+                || keyguardForDozing) && !wakeAndUnlocking;
         if (keyguardForDozing) {
             updatePanelExpansionForKeyguard();
         }
@@ -3385,13 +3015,7 @@
         releaseGestureWakeLock();
         runLaunchTransitionEndRunnable();
         mLaunchTransitionFadingAway = false;
-        updateMediaMetaData(true /* metaDataChanged */, true);
-    }
-
-    public boolean isCollapsing() {
-        return mNotificationPanel.isCollapsing()
-                || mActivityLaunchAnimator.isAnimationPending()
-                || mActivityLaunchAnimator.isAnimationRunning();
+        mPresenter.updateMediaMetaData(true /* metaDataChanged */, true);
     }
 
     public void addPostCollapseAction(Runnable r) {
@@ -3415,12 +3039,13 @@
         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         mLaunchTransitionEndRunnable = endRunnable;
         Runnable hideRunnable = () -> {
+            mKeyguardMonitor.setLaunchTransitionFadingAway(true);
             mLaunchTransitionFadingAway = true;
             if (beforeFading != null) {
                 beforeFading.run();
             }
             updateScrimController();
-            updateMediaMetaData(false, true);
+            mPresenter.updateMediaMetaData(false, true);
             mNotificationPanel.setAlpha(1);
             mNotificationPanel.animate()
                     .alpha(0)
@@ -3505,9 +3130,8 @@
             mLockscreenUserManager.updatePublicMode();
             mEntryManager.updateNotifications();
         }
-        View viewToClick = null;
         if (mStatusBarStateController.leaveOpenOnKeyguardHide()) {
-            if (!mKeyguardRequested) {
+            if (!mStatusBarStateController.isKeyguardRequested()) {
                 mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
             }
             long delay = mKeyguardMonitor.calculateGoingToFullShadeDelay();
@@ -3516,10 +3140,6 @@
                 mDraggedDownRow.setUserLocked(false);
                 mDraggedDownRow = null;
             }
-            if (!mKeyguardRequested) {
-                viewToClick = mPendingRemoteInputView;
-                mPendingRemoteInputView = null;
-            }
 
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
@@ -3530,10 +3150,6 @@
             instantCollapseNotificationPanel();
         }
 
-        if (viewToClick != null && viewToClick.isAttachedToWindow()) {
-            viewToClick.callOnClick();
-        }
-
         // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
         // visibilities so next time we open the panel we know the correct height already.
         if (mQSPanel != null) {
@@ -3575,7 +3191,7 @@
         mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
-        recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
+        mCommandQueue.recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
         mCommandQueue.appTransitionStarting(
                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -3697,15 +3313,43 @@
         }
     }
 
-    protected void showBouncer(boolean scrimmed) {
+    @Override
+    public void showBouncer(boolean scrimmed) {
         mStatusBarKeyguardViewManager.showBouncer(scrimmed);
     }
 
-    private void instantExpandNotificationsPanel() {
+    @Override
+    public void instantExpandNotificationsPanel() {
         // Make our window larger and the panel expanded.
         makeExpandedVisible(true);
         mNotificationPanel.expand(false /* animate */);
-        recomputeDisableFlags(false /* animate */);
+        mCommandQueue.recomputeDisableFlags(false /* animate */);
+    }
+
+    @Override
+    public boolean closeShadeIfOpen() {
+        if (!mNotificationPanel.isFullyCollapsed()) {
+            mCommandQueue.animateCollapsePanels(
+                    CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+            visibilityChanged(false);
+            mAssistManager.hideAssist();
+        }
+        return false;
+    }
+
+    @Override
+    public void postOnShadeExpanded(Runnable executable) {
+        mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
+                new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        if (getStatusBarWindow().getHeight() != getStatusBarHeight()) {
+                            mNotificationPanel.getViewTreeObserver()
+                                    .removeOnGlobalLayoutListener(this);
+                            mNotificationPanel.post(executable);
+                        }
+                    }
+                });
     }
 
     private void instantCollapseNotificationPanel() {
@@ -3714,25 +3358,7 @@
     }
 
     @Override
-    public void onActivated(ActivatableNotificationView view) {
-        onActivated((View) view);
-        mNotificationPanel.setActivatedChild(view);
-    }
-
-    public void onActivated(View view) {
-        mLockscreenGestureLogger.write(
-                MetricsEvent.ACTION_LS_NOTE,
-                0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
-        mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
-        ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
-        if (previousView != null) {
-            previousView.makeInactive(true /* animate */);
-        }
-    }
-
-    @Override
     public void onStatePreChange(int oldState, int newState) {
-
         // If we're visible and switched to SHADE_LOCKED (the user dragged
         // down on the lockscreen), clear notification LED, vibration,
         // ringing.
@@ -3780,7 +3406,7 @@
         updateDozingState();
         checkBarModes();
         updateScrimController();
-        updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
+        mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
                 mUnlockMethodCache.isMethodSecure(),
                 mStatusBarKeyguardViewManager.isOccluded());
@@ -3797,6 +3423,7 @@
                 && DozeParameters.getInstance(mContext).shouldControlScreenOff();
         mNotificationPanel.resetViews(dozingAnimated);
 
+        updateQsExpansionEnabled();
         mKeyguardViewMediator.setAodShowing(mDozing);
 
         //TODO: make these folks listeners of StatusBarStateController.onDozingChanged
@@ -3828,15 +3455,7 @@
         mStatusBarStateController.setIsDozing(dozing);
     }
 
-    @Override
-    public void onActivationReset(ActivatableNotificationView view) {
-        if (view == mNotificationPanel.getActivatedChild()) {
-            mNotificationPanel.setActivatedChild(null);
-            onActivationReset((View)view);
-        }
-    }
-
-    public void onActivationReset(View view) {
+    public void onActivationReset() {
         mKeyguardIndicationController.hideTransientIndication();
     }
 
@@ -3846,7 +3465,7 @@
 
     public void onClosingFinished() {
         runPostCollapseRunnables();
-        if (!isPresenterFullyCollapsed()) {
+        if (!mPresenter.isPresenterFullyCollapsed()) {
             // if we set it not to be focusable when collapsing, we have to undo it when we aborted
             // the closing
             mStatusBarWindowController.setStatusBarFocusable(true);
@@ -3886,22 +3505,6 @@
         }
     }
 
-    @Override
-    public int getMaxNotificationsWhileLocked(boolean recompute) {
-        if (recompute) {
-            mMaxKeyguardNotifications = Math.max(1,
-                    mNotificationPanel.computeMaxKeyguardNotifications(
-                            mMaxAllowedKeyguardNotifications));
-            return mMaxKeyguardNotifications;
-        }
-        return mMaxKeyguardNotifications;
-    }
-
-    @Override
-    public void onUpdateRowStates() {
-        mNotificationPanel.onUpdateRowStates();
-    }
-
     // TODO: Figure out way to remove these.
     public NavigationBarView getNavigationBarView() {
         return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
@@ -3958,184 +3561,6 @@
         }
     }
 
-    public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
-        mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
-        dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
-    }
-
-    @Override
-    public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
-        mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
-        showBouncer(true /* scrimmed */);
-        mPendingRemoteInputView = clicked;
-    }
-
-    @Override
-    public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
-            View clickedView) {
-        if (isKeyguardShowing()) {
-            onLockedRemoteInput(row, clickedView);
-        } else {
-            row.setUserExpanded(true);
-            row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
-        }
-    }
-
-    @Override
-    public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
-        // Skip remote input as doing so will expand the notification shade.
-        return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
-    }
-
-    @Override
-    public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
-            Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
-        final boolean isActivity = pendingIntent.isActivity();
-        if (isActivity) {
-            final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
-                    mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
-            dismissKeyguardThenExecute(() -> {
-                try {
-                    ActivityManager.getService().resumeAppSwitches();
-                } catch (RemoteException e) {
-                }
-
-                boolean handled = defaultHandler.handleClick();
-
-                // close the shade if it was open
-                if (handled && !mNotificationPanel.isFullyCollapsed()) {
-                    animateCollapsePanels(
-                            CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
-                    visibilityChanged(false);
-                    mAssistManager.hideAssist();
-
-                    // Wait for activity start.
-                    return true;
-                } else {
-                    return false;
-                }
-
-            }, afterKeyguardGone);
-            return true;
-        } else {
-            return defaultHandler.handleClick();
-        }
-    }
-
-    protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
-            String notificationKey) {
-        // Clear pending remote view, as we do not want to trigger pending remote input view when
-        // it's called by other code
-        mPendingWorkRemoteInputView = null;
-        // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
-        final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
-                null, userId);
-        if (newIntent == null) {
-            return false;
-        }
-        final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
-        callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
-        callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
-        callBackIntent.setPackage(mContext.getPackageName());
-
-        PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
-                mContext,
-                0,
-                callBackIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT |
-                        PendingIntent.FLAG_ONE_SHOT |
-                        PendingIntent.FLAG_IMMUTABLE);
-        newIntent.putExtra(
-                Intent.EXTRA_INTENT,
-                callBackPendingIntent.getIntentSender());
-        try {
-            ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
-                    null /*options*/);
-        } catch (RemoteException ex) {
-            // ignore
-        }
-        return true;
-        // End old BaseStatusBar.startWorkChallengeIfNecessary.
-    }
-
-    @Override
-    public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
-            View clicked) {
-        // Collapse notification and show work challenge
-        animateCollapsePanels();
-        startWorkChallengeIfNecessary(userId, null, null);
-        // Add pending remote input view after starting work challenge, as starting work challenge
-        // will clear all previous pending review view
-        mPendingWorkRemoteInputView = clicked;
-    }
-
-    @Override
-    public void onWorkChallengeChanged() {
-        if (mPendingWorkRemoteInputView != null
-                && !mLockscreenUserManager.isAnyProfilePublicMode()) {
-            // Expand notification panel and the notification row, then click on remote input view
-            final Runnable clickPendingViewRunnable = () -> {
-                final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
-                if (pendingWorkRemoteInputView == null) {
-                    return;
-                }
-
-                // Climb up the hierarchy until we get to the container for this row.
-                ViewParent p = pendingWorkRemoteInputView.getParent();
-                while (!(p instanceof ExpandableNotificationRow)) {
-                    if (p == null) {
-                        return;
-                    }
-                    p = p.getParent();
-                }
-
-                final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
-                ViewParent viewParent = row.getParent();
-                if (viewParent instanceof NotificationStackScrollLayout) {
-                    final NotificationStackScrollLayout scrollLayout =
-                            (NotificationStackScrollLayout) viewParent;
-                    row.makeActionsVisibile();
-                    row.post(() -> {
-                        final Runnable finishScrollingCallback = () -> {
-                            mPendingWorkRemoteInputView.callOnClick();
-                            mPendingWorkRemoteInputView = null;
-                            scrollLayout.setFinishScrollingCallback(null);
-                        };
-                        if (scrollLayout.scrollTo(row)) {
-                            // It scrolls! So call it when it's finished.
-                            scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
-                        } else {
-                            // It does not scroll, so call it now!
-                            finishScrollingCallback.run();
-                        }
-                    });
-                }
-            };
-            mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
-                    new ViewTreeObserver.OnGlobalLayoutListener() {
-                        @Override
-                        public void onGlobalLayout() {
-                            if (mNotificationPanel.mStatusBar.getStatusBarWindow()
-                                    .getHeight() != mNotificationPanel.mStatusBar
-                                            .getStatusBarHeight()) {
-                                mNotificationPanel.getViewTreeObserver()
-                                        .removeOnGlobalLayoutListener(this);
-                                mNotificationPanel.post(clickPendingViewRunnable);
-                            }
-                        }
-                    });
-            instantExpandNotificationsPanel();
-        }
-    }
-
-    @Override
-    public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
-        mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
-        if (mState == StatusBarState.KEYGUARD && nowExpanded) {
-            goToLockedShade(clickedEntry.row);
-        }
-    }
-
     /**
      * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
      */
@@ -4149,7 +3574,7 @@
         mBouncerShowing = bouncerShowing;
         if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
         updateHideIconsForBouncer(true /* animate */);
-        recomputeDisableFlags(true /* animate */);
+        mCommandQueue.recomputeDisableFlags(true /* animate */);
         updateScrimController();
     }
 
@@ -4273,25 +3698,6 @@
     }
 
     @Override
-    public void wakeUpIfDozing(long time, View where) {
-        if (mDozing) {
-            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-            pm.wakeUp(time, "com.android.systemui:NODOZE");
-            mWakeUpComingFromTouch = true;
-            where.getLocationInWindow(mTmpInt2);
-            mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
-                    mTmpInt2[1] + where.getHeight() / 2);
-            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
-            mFalsingManager.onScreenOnFromTouch();
-        }
-    }
-
-    @Override
-    public boolean isDeviceLocked(int userId) {
-        return mKeyguardManager.isDeviceLocked(userId);
-    }
-
-    @Override
     public void appTransitionCancelled() {
         getComponent(Divider.class).onAppTransitionFinished();
     }
@@ -4669,8 +4075,6 @@
 
     protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
 
-    private AboveShelfObserver mAboveShelfObserver;
-
     // handling reordering
     protected VisualStabilityManager mVisualStabilityManager;
 
@@ -4688,7 +4092,6 @@
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     protected KeyguardManager mKeyguardManager;
-    private LockPatternUtils mLockPatternUtils;
     private DeviceProvisionedController mDeviceProvisionedController
             = Dependency.get(DeviceProvisionedController.class);
 
@@ -4707,28 +4110,10 @@
 
     protected AssistManager mAssistManager;
 
-    protected boolean mVrMode;
-
     public boolean isDeviceInteractive() {
         return mDeviceInteractive;
     }
 
-    @Override  // NotificationData.Environment
-    public boolean isDeviceProvisioned() {
-        return mDeviceProvisionedController.isDeviceProvisioned();
-    }
-
-    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
-        @Override
-        public void onVrStateChanged(boolean enabled) {
-            mVrMode = enabled;
-        }
-    };
-
-    public boolean isDeviceInVrMode() {
-        return mVrMode;
-    }
-
     private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -4754,182 +4139,13 @@
     };
 
     @Override
-    public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
-        RemoteInputController controller = mRemoteInputManager.getController();
-        if (controller.isRemoteInputActive(row.getEntry())
-                && !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
-            // We have an active remote input typed and the user clicked on the notification.
-            // this was probably unintentional, so we're closing the edit text instead.
-            controller.closeRemoteInputs();
-            return;
-        }
-        Notification notification = sbn.getNotification();
-        final PendingIntent intent = notification.contentIntent != null
-                ? notification.contentIntent
-                : notification.fullScreenIntent;
-        final String notificationKey = sbn.getKey();
-
-        boolean isActivityIntent = intent.isActivity();
-        final boolean afterKeyguardGone = isActivityIntent
-                && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
-                mLockscreenUserManager.getCurrentUserId());
-        final boolean wasOccluded = mIsOccluded;
-        boolean showOverLockscreen = mStatusBarKeyguardViewManager.isShowing()
-                && PreviewInflater.wouldShowOverLockscreen(mContext,
-                intent.getIntent(),
-                mLockscreenUserManager.getCurrentUserId());
-        OnDismissAction postKeyguardAction = () -> {
-            // TODO: Some of this code may be able to move to NotificationEntryManager.
-            if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
-                // Release the HUN notification to the shade.
-
-                if (isPresenterFullyCollapsed()) {
-                    HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
-                }
-                //
-                // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
-                // become canceled shortly by NoMan, but we can't assume that.
-                mHeadsUpManager.removeNotification(sbn.getKey(),
-                        true /* releaseImmediately */);
-            }
-            StatusBarNotification parentToCancel = null;
-            if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
-                StatusBarNotification summarySbn =
-                        mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification();
-                if (shouldAutoCancel(summarySbn)) {
-                    parentToCancel = summarySbn;
-                }
-            }
-            final StatusBarNotification parentToCancelFinal = parentToCancel;
-            final Runnable runnable = () -> {
-                try {
-                    // The intent we are sending is for the application, which
-                    // won't have permission to immediately start an activity after
-                    // the user switches to home.  We know it is safe to do at this
-                    // point, so make sure new activity switches are now allowed.
-                    ActivityManager.getService().resumeAppSwitches();
-                } catch (RemoteException e) {
-                }
-                int launchResult = ActivityManager.START_CANCELED;
-                if (intent != null) {
-                    // If we are launching a work activity and require to launch
-                    // separate work challenge, we defer the activity action and cancel
-                    // notification until work challenge is unlocked.
-                    if (isActivityIntent) {
-                        final int userId = intent.getCreatorUserHandle().getIdentifier();
-                        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
-                                && mKeyguardManager.isDeviceLocked(userId)) {
-                            // TODO(b/28935539): should allow certain activities to
-                            // bypass work challenge
-                            if (startWorkChallengeIfNecessary(userId, intent.getIntentSender(),
-                                    notificationKey)) {
-                                // Show work challenge, do not run PendingIntent and
-                                // remove notification
-                                collapseOnMainThread();
-                                return;
-                            }
-                        }
-                    }
-                    Intent fillInIntent = null;
-                    Entry entry = row.getEntry();
-                    CharSequence remoteInputText = null;
-                    if (!TextUtils.isEmpty(entry.remoteInputText)) {
-                        remoteInputText = entry.remoteInputText;
-                    }
-                    if (!TextUtils.isEmpty(remoteInputText)
-                            && !controller.isSpinning(entry.key)) {
-                        fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
-                                remoteInputText.toString());
-                    }
-                    RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
-                            row, wasOccluded);
-                    try {
-                        if (adapter != null) {
-                            ActivityTaskManager.getService()
-                                    .registerRemoteAnimationForNextActivityStart(
-                                            intent.getCreatorPackage(), adapter);
-                        }
-                        launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
-                                null, null, getActivityOptions(adapter));
-                        mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
-                    } catch (RemoteException | PendingIntent.CanceledException e) {
-                        // the stack trace isn't very helpful here.
-                        // Just log the exception message.
-                        Log.w(TAG, "Sending contentIntent failed: " + e);
-
-                        // TODO: Dismiss Keyguard.
-                    }
-                    if (isActivityIntent) {
-                        mAssistManager.hideAssist();
-                    }
-                }
-                if (shouldCollapse()) {
-                    collapseOnMainThread();
-                }
-
-                final int count =
-                        mEntryManager.getNotificationData().getActiveNotifications().size();
-                final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
-                final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
-                        rank, count, true);
-                try {
-                    mBarService.onNotificationClick(notificationKey, nv);
-                } catch (RemoteException ex) {
-                    // system process is dead if we're here.
-                }
-                if (parentToCancelFinal != null) {
-                    removeNotification(parentToCancelFinal);
-                }
-                if (shouldAutoCancel(sbn)
-                        || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
-                                notificationKey)) {
-                    // Automatically remove all notifications that we may have kept around longer
-                    removeNotification(sbn);
-                }
-
-                mIsCollapsingToShowActivityOverLockscreen = false;
-            };
-
-            if (showOverLockscreen) {
-                addPostCollapseAction(runnable);
-                collapsePanel(true /* animate */);
-            } else if (mStatusBarKeyguardViewManager.isShowing()
-                    && mStatusBarKeyguardViewManager.isOccluded()) {
-                mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
-                collapsePanel(true /* animate */);
-            } else {
-                new Thread(runnable).start();
-            }
-
-            return !mNotificationPanel.isFullyCollapsed();
-        };
-        if (showOverLockscreen) {
-            mIsCollapsingToShowActivityOverLockscreen = true;
-            postKeyguardAction.onDismiss();
-        } else {
-            dismissKeyguardThenExecute(postKeyguardAction, afterKeyguardGone);
-        }
-    }
-
-    private void collapseOnMainThread() {
-        if (Looper.getMainLooper().isCurrentThread()) {
-            collapsePanel();
-        } else {
-            Dependency.get(Dependency.MAIN_HANDLER).post(this::collapsePanel);
-        }
-    }
-
-    private boolean shouldCollapse() {
-        return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending();
-    }
-
     public void collapsePanel(boolean animate) {
         if (animate) {
             boolean willCollapse = collapsePanel();
             if (!willCollapse) {
                 runPostCollapseRunnables();
             }
-        } else if (!isPresenterFullyCollapsed()) {
+        } else if (!mPresenter.isPresenterFullyCollapsed()) {
             instantCollapseNotificationPanel();
             visibilityChanged(false);
         } else {
@@ -4937,7 +4153,8 @@
         }
     }
 
-    private boolean collapsePanel() {
+    @Override
+    public boolean collapsePanel() {
         if (!mNotificationPanel.isFullyCollapsed()) {
             // close the shade if it was open
             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
@@ -4950,59 +4167,8 @@
         }
     }
 
-    private void removeNotification(StatusBarNotification notification) {
-        // We have to post it to the UI thread for synchronization
-        mHandler.post(() -> {
-            Runnable removeRunnable =
-                    () -> mEntryManager.performRemoveNotification(notification);
-            if (isCollapsing()) {
-                // To avoid lags we're only performing the remove
-                // after the shade was collapsed
-                addPostCollapseAction(removeRunnable);
-            } else {
-                removeRunnable.run();
-            }
-        });
-    }
-
     protected NotificationListener mNotificationListener;
 
-    @Override  // NotificationData.Environment
-    public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
-        final int notificationUserId = n.getUserId();
-        if (DEBUG && MULTIUSER_DEBUG) {
-            Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
-                    mLockscreenUserManager.getCurrentUserId(), notificationUserId));
-        }
-        return mLockscreenUserManager.isCurrentProfile(notificationUserId);
-    }
-
-    @Override
-    public NotificationGroupManager getGroupManager() {
-        return mGroupManager;
-    }
-
-    @Override
-    public void startNotificationGutsIntent(final Intent intent, final int appUid,
-            ExpandableNotificationRow row) {
-        dismissKeyguardThenExecute(() -> {
-            AsyncTask.execute(() -> {
-                int launchResult = TaskStackBuilder.create(mContext)
-                        .addNextIntentWithParentStack(intent)
-                        .startActivities(getActivityOptions(
-                                mActivityLaunchAnimator.getLaunchAnimation(row, mIsOccluded)),
-                                new UserHandle(UserHandle.getUserId(appUid)));
-                mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
-                if (shouldCollapse()) {
-                    // Putting it back on the main thread, since we're touching views
-                    mStatusBarWindow.post(() -> animateCollapsePanels(
-                            CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
-                }
-            });
-            return true;
-        }, false /* afterKeyguardGone */);
-    }
-
     public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
         if (snoozeOption.getSnoozeCriterion() != null) {
             mNotificationListener.snoozeNotification(sbn.getKey(),
@@ -5063,7 +4229,7 @@
             // Immediately update the icon hidden state, since that should only apply if we're
             // staying fullscreen.
             mWereIconsJustHidden = false;
-            recomputeDisableFlags(true);
+            mCommandQueue.recomputeDisableFlags(true);
         }
         updateHideIconsForBouncer(true /* animate */);
     }
@@ -5076,24 +4242,6 @@
         KeyboardShortcuts.dismiss();
     }
 
-    @Override  // NotificationData.Environment
-    public boolean shouldHideNotifications(int userId) {
-        return mLockscreenUserManager.shouldHideNotifications(userId);
-    }
-
-    @Override // NotificationDate.Environment
-    public boolean shouldHideNotifications(String key) {
-        return mLockscreenUserManager.shouldHideNotifications(key);
-    }
-
-    /**
-     * Returns true if we're on a secure lockscreen.
-     */
-    @Override  // NotificationData.Environment
-    public boolean isSecurelyLocked(int userId) {
-        return mLockscreenUserManager.isLockscreenPublicMode(userId);
-    }
-
     /**
      * Called when the notification panel layouts
      */
@@ -5105,8 +4253,8 @@
         if (mState == StatusBarState.KEYGUARD) {
             // Since the number of notifications is determined based on the height of the view, we
             // need to update them.
-            int maxBefore = getMaxNotificationsWhileLocked(false /* recompute */);
-            int maxNotifications = getMaxNotificationsWhileLocked(true /* recompute */);
+            int maxBefore = mPresenter.getMaxNotificationsWhileLocked(false /* recompute */);
+            int maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
             if (maxBefore != maxNotifications) {
                 mViewHierarchyManager.updateRowStates();
             }
@@ -5114,7 +4262,7 @@
     }
 
     public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
-        if (!isDeviceProvisioned()) return;
+        if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
 
         final boolean afterKeyguardGone = intent.isActivity()
                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
@@ -5148,18 +4296,7 @@
         }, afterKeyguardGone);
     }
 
-    private boolean shouldAutoCancel(StatusBarNotification sbn) {
-        int flags = sbn.getNotification().flags;
-        if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
-            return false;
-        }
-        if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
-            return false;
-        }
-        return true;
-    }
-
-    protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
+    public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
         ActivityOptions options;
         if (animationAdapter != null) {
             options = ActivityOptions.makeRemoteAnimation(animationAdapter);
@@ -5276,28 +4413,4 @@
     public NotificationGutsManager getGutsManager() {
         return mGutsManager;
     }
-
-    @Override
-    public boolean isPresenterLocked() {
-        return mState == StatusBarState.KEYGUARD;
-    }
-
-    @Override
-    public Handler getHandler() {
-        return mHandler;
-    }
-
-    private final NotificationInfo.CheckSaveListener mCheckSaveListener =
-            (Runnable saveImportance, StatusBarNotification sbn) -> {
-                // If the user has security enabled, show challenge if the setting is changed.
-                if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
-                        && mKeyguardManager.isKeyguardLocked()) {
-                    onLockedNotificationImportanceChange(() -> {
-                        saveImportance.run();
-                        return true;
-                    });
-                } else {
-                    saveImportance.run();
-                }
-            };
 }
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 ac3608b..c560301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
 
@@ -43,6 +43,7 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
@@ -124,6 +125,8 @@
     // Dismiss action to be launched when we stop dozing or the keyguard is gone.
     private DismissWithActionRequest mPendingWakeupAction;
     private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+    private final NotificationMediaManager mMediaManager =
+            Dependency.get(NotificationMediaManager.class);
 
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -381,7 +384,7 @@
         boolean isOccluding = !mOccluded && occluded;
         mOccluded = occluded;
         if (mShowing) {
-            mStatusBar.updateMediaMetaData(false, animate && !occluded);
+            mMediaManager.updateMediaMetaData(false, animate && !occluded);
         }
         mStatusBarWindowController.setKeyguardOccluded(occluded);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
new file mode 100644
index 0000000..edfc049
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static com.android.systemui.Dependency.MAIN_HANDLER;
+import static com.android.systemui.SysUiServiceProvider.getComponent;
+import static com.android.systemui.statusbar.phone.StatusBar.CLOSE_PANEL_WHEN_EMPTIED;
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
+import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
+import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
+import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.KeyguardManager;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.TaskStackBuilder;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.RemoteAnimationAdapter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.TextView;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
+import com.android.systemui.R;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback;
+import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AboveShelfObserver;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
+import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.HeadsUpUtil;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.PreviewInflater;
+
+public class StatusBarNotificationPresenter implements NotificationPresenter {
+
+    private final LockscreenGestureLogger mLockscreenGestureLogger =
+            Dependency.get(LockscreenGestureLogger.class);
+
+    private static final String TAG = "StatusBarNotificationPresenter";
+
+    private final ShadeController mShadeController = Dependency.get(ShadeController.class);
+    private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
+    private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
+    private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+    private final NotificationViewHierarchyManager mViewHierarchyManager =
+            Dependency.get(NotificationViewHierarchyManager.class);
+    private final NotificationLockscreenUserManager mLockscreenUserManager =
+            Dependency.get(NotificationLockscreenUserManager.class);
+    private final StatusBarStateController mStatusBarStateController =
+            Dependency.get(StatusBarStateController.class);
+    private final NotificationEntryManager mEntryManager =
+            Dependency.get(NotificationEntryManager.class);
+    private final NotificationMediaManager mMediaManager =
+            Dependency.get(NotificationMediaManager.class);
+    private final NotificationRemoteInputManager mRemoteInputManager =
+            Dependency.get(NotificationRemoteInputManager.class);
+    private final NotificationGroupManager mGroupManager =
+            Dependency.get(NotificationGroupManager.class);
+    private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
+            (StatusBarRemoteInputCallback) Dependency.get(Callback.class);
+    protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+
+    private final NotificationPanelView mNotificationPanel;
+    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final AboveShelfObserver mAboveShelfObserver;
+    private final DozeScrimController mDozeScrimController;
+    private final ScrimController mScrimController;
+    private final Context mContext;
+    private final CommandQueue mCommandQueue;
+
+    private final AccessibilityManager mAccessibilityManager;
+    private final LockPatternUtils mLockPatternUtils;
+    private final KeyguardManager mKeyguardManager;
+    private final ActivityLaunchAnimator mActivityLaunchAnimator;
+    private final int mMaxAllowedKeyguardNotifications;
+    private final IStatusBarService mBarService;
+    private boolean mReinflateNotificationsOnUserSwitched;
+    private final UnlockMethodCache mUnlockMethodCache;
+    private TextView mNotificationPanelDebugText;
+
+    protected boolean mVrMode;
+    private int mMaxKeyguardNotifications;
+    private boolean mIsCollapsingToShowActivityOverLockscreen;
+
+    public StatusBarNotificationPresenter(Context context, NotificationPanelView panel,
+            HeadsUpManagerPhone headsUp, StatusBarWindowView statusBarWindow,
+            ViewGroup stackScroller, DozeScrimController dozeScrimController,
+            ScrimController scrimController,
+            ActivityLaunchAnimator.Callback launchAnimatorCallback) {
+        mContext = context;
+        mNotificationPanel = panel;
+        mHeadsUpManager = headsUp;
+        mCommandQueue = getComponent(context, CommandQueue.class);
+        mAboveShelfObserver = new AboveShelfObserver(stackScroller);
+        mAboveShelfObserver.setListener(statusBarWindow.findViewById(
+                R.id.notification_container_parent));
+        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+        mDozeScrimController = dozeScrimController;
+        mScrimController = scrimController;
+        mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
+        mLockPatternUtils = new LockPatternUtils(context);
+        mKeyguardManager = context.getSystemService(KeyguardManager.class);
+        mMaxAllowedKeyguardNotifications = context.getResources().getInteger(
+                R.integer.keyguard_max_notification_count);
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mActivityLaunchAnimator = new ActivityLaunchAnimator(statusBarWindow,
+                launchAnimatorCallback,
+                mNotificationPanel,
+                (NotificationListContainer) stackScroller);
+
+        if (MULTIUSER_DEBUG) {
+            mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
+            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
+        }
+
+        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
+                Context.VR_SERVICE));
+        if (vrManager != null) {
+            try {
+                vrManager.registerListener(mVrStateCallbacks);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+            }
+        }
+        mRemoteInputManager.setUpWithPresenter(this,
+                Dependency.get(NotificationRemoteInputManager.Callback.class),
+                mNotificationPanel.createRemoteInputDelegate());
+        mRemoteInputManager.getController().addCallback(
+                Dependency.get(StatusBarWindowController.class));
+
+        NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller;
+        Dependency.get(InitController.class).addPostInitTask(() -> {
+            mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
+            mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager);
+            mLockscreenUserManager.setUpWithPresenter(this);
+            mMediaManager.setUpWithPresenter(this);
+            Dependency.get(NotificationGutsManager.class).setUpWithPresenter(this,
+                    notifListContainer, mCheckSaveListener, mOnSettingsClickListener);
+
+            onUserSwitched(mLockscreenUserManager.getCurrentUserId());
+        });
+    }
+
+    public void onDensityOrFontScaleChanged() {
+        if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
+            mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
+        } else {
+            mReinflateNotificationsOnUserSwitched = true;
+        }
+    }
+
+    @Override
+    public ActivityLaunchAnimator getActivityLaunchAnimator() {
+        return mActivityLaunchAnimator;
+    }
+
+    @Override
+    public boolean isCollapsing() {
+        return mNotificationPanel.isCollapsing()
+                || mActivityLaunchAnimator.isAnimationPending()
+                || mActivityLaunchAnimator.isAnimationRunning();
+    }
+
+    @Override
+    public boolean isCollapsingToShowActivityOverLockscreen() {
+        return mIsCollapsingToShowActivityOverLockscreen;
+    }
+
+    @Override
+    public void onPerformRemoveNotification(StatusBarNotification n) {
+        if (mNotificationPanel.hasPulsingNotifications() &&
+                    !mAmbientPulseManager.hasNotifications()) {
+            // We were showing a pulse for a notification, but no notifications are pulsing anymore.
+            // Finish the pulse.
+            mDozeScrimController.pulseOutNow();
+        }
+    }
+
+    @Override
+    public void updateNotificationViews() {
+        // The function updateRowStates depends on both of these being non-null, so check them here.
+        // We may be called before they are set from DeviceProvisionedController's callback.
+        if (mScrimController == null) return;
+
+        // Do not modify the notifications during collapse.
+        if (isCollapsing()) {
+            mShadeController.addPostCollapseAction(this::updateNotificationViews);
+            return;
+        }
+
+        mViewHierarchyManager.updateNotificationViews();
+
+        mNotificationPanel.updateNotificationViews();
+    }
+
+    @Override
+    public void onNotificationAdded(Entry shadeEntry) {
+        // Recalculate the position of the sliding windows and the titles.
+        mShadeController.updateAreThereNotifications();
+    }
+
+    @Override
+    public void onNotificationUpdated(StatusBarNotification notification) {
+        mShadeController.updateAreThereNotifications();
+    }
+
+    @Override
+    public void onNotificationRemoved(String key, StatusBarNotification old) {
+        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) {
+                    mCommandQueue.animateCollapsePanels();
+                } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
+                        && !isCollapsing()) {
+                    mShadeController.goToKeyguard();
+                }
+            }
+        }
+        mShadeController.updateAreThereNotifications();
+    }
+
+    public boolean hasActiveNotifications() {
+        return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+    }
+
+    @Override
+    public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+        if (mShadeController.isDozing()) {
+            return false;
+        }
+
+        if (mShadeController.isOccluded()) {
+            boolean devicePublic = mLockscreenUserManager.
+                    isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+            boolean userPublic = devicePublic
+                    || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+            boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+            if (userPublic && needsRedaction) {
+                return false;
+            }
+        }
+
+        if (!mCommandQueue.panelsEnabled()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (sbn.getNotification().fullScreenIntent != null) {
+            if (mAccessibilityManager.isTouchExplorationEnabled()) {
+                if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
+                return false;
+            } else {
+                // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
+                return !mKeyguardMonitor.isShowing()
+                        || mShadeController.isOccluded();
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void onUserSwitched(int newUserId) {
+        // Begin old BaseStatusBar.userSwitched
+        mHeadsUpManager.setUser(newUserId);
+        // End old BaseStatusBar.userSwitched
+        if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
+        mCommandQueue.animateCollapsePanels();
+        if (mReinflateNotificationsOnUserSwitched) {
+            mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
+            mReinflateNotificationsOnUserSwitched = false;
+        }
+        updateNotificationViews();
+        mMediaManager.clearCurrentMediaNotification();
+        mShadeController.setLockscreenUser(newUserId);
+        updateMediaMetaData(true, false);
+    }
+
+    @Override
+    public void onBindRow(Entry entry, PackageManager pmUser,
+            StatusBarNotification sbn, ExpandableNotificationRow row) {
+        row.setAboveShelfChangedListener(mAboveShelfObserver);
+        row.setSecureStateProvider(mUnlockMethodCache::canSkipBouncer);
+    }
+
+    @Override
+    public boolean isPresenterFullyCollapsed() {
+        return mNotificationPanel.isFullyCollapsed();
+    }
+
+    @Override
+    public void onActivated(ActivatableNotificationView view) {
+        onActivated();
+        if (view != null) mNotificationPanel.setActivatedChild(view);
+    }
+
+    public void onActivated() {
+        mLockscreenGestureLogger.write(
+                MetricsEvent.ACTION_LS_NOTE,
+                0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+        mNotificationPanel.showTransientIndication(R.string.notification_tap_again);
+        ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
+        if (previousView != null) {
+            previousView.makeInactive(true /* animate */);
+        }
+    }
+
+    @Override
+    public void onActivationReset(ActivatableNotificationView view) {
+        if (view == mNotificationPanel.getActivatedChild()) {
+            mNotificationPanel.setActivatedChild(null);
+            mShadeController.onActivationReset();
+        }
+    }
+
+    @Override
+    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+        mMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation);
+    }
+
+    @Override
+    public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
+        RemoteInputController controller = mRemoteInputManager.getController();
+        if (controller.isRemoteInputActive(row.getEntry())
+                && !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
+            // We have an active remote input typed and the user clicked on the notification.
+            // this was probably unintentional, so we're closing the edit text instead.
+            controller.closeRemoteInputs();
+            return;
+        }
+        Notification notification = sbn.getNotification();
+        final PendingIntent intent = notification.contentIntent != null
+                ? notification.contentIntent
+                : notification.fullScreenIntent;
+        final String notificationKey = sbn.getKey();
+
+        boolean isActivityIntent = intent.isActivity();
+        final boolean afterKeyguardGone = isActivityIntent
+                && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
+                mLockscreenUserManager.getCurrentUserId());
+        final boolean wasOccluded = mShadeController.isOccluded();
+        boolean showOverLockscreen = mKeyguardMonitor.isShowing()
+                && PreviewInflater.wouldShowOverLockscreen(mContext,
+                intent.getIntent(),
+                mLockscreenUserManager.getCurrentUserId());
+        OnDismissAction postKeyguardAction = () -> {
+            // TODO: Some of this code may be able to move to NotificationEntryManager.
+            if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
+                // Release the HUN notification to the shade.
+
+                if (isPresenterFullyCollapsed()) {
+                    HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
+                }
+                //
+                // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
+                // become canceled shortly by NoMan, but we can't assume that.
+                mHeadsUpManager.removeNotification(sbn.getKey(),
+                        true /* releaseImmediately */);
+            }
+            StatusBarNotification parentToCancel = null;
+            if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
+                StatusBarNotification summarySbn =
+                        mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification();
+                if (shouldAutoCancel(summarySbn)) {
+                    parentToCancel = summarySbn;
+                }
+            }
+            final StatusBarNotification parentToCancelFinal = parentToCancel;
+            final Runnable runnable = () -> {
+                try {
+                    // The intent we are sending is for the application, which
+                    // won't have permission to immediately start an activity after
+                    // the user switches to home.  We know it is safe to do at this
+                    // point, so make sure new activity switches are now allowed.
+                    ActivityManager.getService().resumeAppSwitches();
+                } catch (RemoteException e) {
+                }
+                int launchResult = ActivityManager.START_CANCELED;
+                if (intent != null) {
+                    // If we are launching a work activity and require to launch
+                    // separate work challenge, we defer the activity action and cancel
+                    // notification until work challenge is unlocked.
+                    if (isActivityIntent) {
+                        final int userId = intent.getCreatorUserHandle().getIdentifier();
+                        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+                                && mKeyguardManager.isDeviceLocked(userId)) {
+                            // TODO(b/28935539): should allow certain activities to
+                            // bypass work challenge
+                            if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
+                                    intent.getIntentSender(), notificationKey)) {
+                                // Show work challenge, do not run PendingIntent and
+                                // remove notification
+                                collapseOnMainThread();
+                                return;
+                            }
+                        }
+                    }
+                    Intent fillInIntent = null;
+                    Entry entry = row.getEntry();
+                    CharSequence remoteInputText = null;
+                    if (!TextUtils.isEmpty(entry.remoteInputText)) {
+                        remoteInputText = entry.remoteInputText;
+                    }
+                    if (!TextUtils.isEmpty(remoteInputText)
+                            && !controller.isSpinning(entry.key)) {
+                        fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
+                                remoteInputText.toString());
+                    }
+                    RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
+                            row, wasOccluded);
+                    try {
+                        if (adapter != null) {
+                            ActivityTaskManager.getService()
+                                    .registerRemoteAnimationForNextActivityStart(
+                                            intent.getCreatorPackage(), adapter);
+                        }
+                        launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
+                                null, null, getActivityOptions(adapter));
+                        mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
+                    } catch (RemoteException | PendingIntent.CanceledException e) {
+                        // the stack trace isn't very helpful here.
+                        // Just log the exception message.
+                        Log.w(TAG, "Sending contentIntent failed: " + e);
+
+                        // TODO: Dismiss Keyguard.
+                    }
+                    if (isActivityIntent) {
+                        mAssistManager.hideAssist();
+                    }
+                }
+                if (shouldCollapse()) {
+                    collapseOnMainThread();
+                }
+
+                final int count =
+                        mEntryManager.getNotificationData().getActiveNotifications().size();
+                final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+                final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
+                        rank, count, true);
+                try {
+                    mBarService.onNotificationClick(notificationKey, nv);
+                } catch (RemoteException ex) {
+                    // system process is dead if we're here.
+                }
+                if (parentToCancelFinal != null) {
+                    removeNotification(parentToCancelFinal);
+                }
+                if (shouldAutoCancel(sbn)
+                        || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
+                                notificationKey)) {
+                    // Automatically remove all notifications that we may have kept around longer
+                    removeNotification(sbn);
+                }
+                mIsCollapsingToShowActivityOverLockscreen = false;
+            };
+
+            if (showOverLockscreen) {
+                mShadeController.addPostCollapseAction(runnable);
+                mShadeController.collapsePanel(true /* animate */);
+            } else if (mKeyguardMonitor.isShowing()
+                    && mShadeController.isOccluded()) {
+                mShadeController.addAfterKeyguardGoneRunnable(runnable);
+                mShadeController.collapsePanel();
+            } else {
+                new Thread(runnable).start();
+            }
+
+            return !mNotificationPanel.isFullyCollapsed();
+        };
+        if (showOverLockscreen) {
+            mIsCollapsingToShowActivityOverLockscreen = true;
+            postKeyguardAction.onDismiss();
+        } else {
+            mActivityStarter.dismissKeyguardThenExecute(
+                    postKeyguardAction, null /* cancel */, afterKeyguardGone);
+        }
+    }
+
+    private void removeNotification(StatusBarNotification notification) {
+        // We have to post it to the UI thread for synchronization
+        Dependency.get(MAIN_HANDLER).post(() -> {
+            Runnable removeRunnable =
+                    () -> mEntryManager.performRemoveNotification(notification);
+            if (isCollapsing()) {
+                // To avoid lags we're only performing the remove
+                // after the shade was collapsed
+                mShadeController.addPostCollapseAction(removeRunnable);
+            } else {
+                removeRunnable.run();
+            }
+        });
+    }
+
+    @Override
+    public void startNotificationGutsIntent(final Intent intent, final int appUid,
+            ExpandableNotificationRow row) {
+        mActivityStarter.dismissKeyguardThenExecute(() -> {
+            AsyncTask.execute(() -> {
+                int launchResult = TaskStackBuilder.create(mContext)
+                        .addNextIntentWithParentStack(intent)
+                        .startActivities(getActivityOptions(
+                                mActivityLaunchAnimator.getLaunchAnimation(
+                                        row, mShadeController.isOccluded())),
+                                new UserHandle(UserHandle.getUserId(appUid)));
+                mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
+                if (shouldCollapse()) {
+                    // Putting it back on the main thread, since we're touching views
+                    Dependency.get(MAIN_HANDLER).post(() -> mCommandQueue.animateCollapsePanels(
+                            CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
+                }
+            });
+            return true;
+        }, null, false /* afterKeyguardGone */);
+    }
+
+    @Override
+    public int getMaxNotificationsWhileLocked(boolean recompute) {
+        if (recompute) {
+            mMaxKeyguardNotifications = Math.max(1,
+                    mNotificationPanel.computeMaxKeyguardNotifications(
+                            mMaxAllowedKeyguardNotifications));
+            return mMaxKeyguardNotifications;
+        }
+        return mMaxKeyguardNotifications;
+    }
+
+    @Override
+    public void onUpdateRowStates() {
+        mNotificationPanel.onUpdateRowStates();
+    }
+
+    @Override
+    public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
+        mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
+        if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
+            mShadeController.goToLockedShade(clickedEntry.row);
+        }
+    }
+
+    @Override
+    public boolean isDeviceInVrMode() {
+        return mVrMode;
+    }
+
+    @Override
+    public boolean isPresenterLocked() {
+        return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+    }
+
+    private void collapseOnMainThread() {
+        if (Looper.getMainLooper().isCurrentThread()) {
+            mShadeController.collapsePanel();
+        } else {
+            Dependency.get(MAIN_HANDLER).post(mShadeController::collapsePanel);
+        }
+    }
+
+    private boolean shouldCollapse() {
+        return mStatusBarStateController.getState() != StatusBarState.SHADE
+                || !mActivityLaunchAnimator.isAnimationPending();
+    }
+
+    private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
+        mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        mActivityStarter.dismissKeyguardThenExecute(dismissAction, null,
+                true /* afterKeyguardGone */);
+    }
+
+    private static boolean shouldAutoCancel(StatusBarNotification sbn) {
+        int flags = sbn.getNotification().flags;
+        if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
+            return false;
+        }
+        if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+            return false;
+        }
+        return true;
+    }
+
+    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+        @Override
+        public void onVrStateChanged(boolean enabled) {
+            mVrMode = enabled;
+        }
+    };
+
+    private final CheckSaveListener mCheckSaveListener = new CheckSaveListener() {
+        @Override
+        public void checkSave(Runnable saveImportance, StatusBarNotification sbn) {
+            int state = mStatusBarStateController.getState();
+            // If the user has security enabled, show challenge if the setting is changed.
+            if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
+                    && mKeyguardManager.isKeyguardLocked()) {
+                onLockedNotificationImportanceChange(() -> {
+                    saveImportance.run();
+                    return true;
+                });
+            } else {
+                saveImportance.run();
+            }
+        }
+    };
+
+    private final OnSettingsClickListener mOnSettingsClickListener = new OnSettingsClickListener() {
+        @Override
+        public void onSettingsClick(String key) {
+            try {
+                mBarService.onNotificationSettingsViewed(key);
+            } catch (RemoteException e) {
+                // if we're here we're dead
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
new file mode 100644
index 0000000..06f9658
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
+
+import static com.android.systemui.SysUiServiceProvider.getComponent;
+import static com.android.systemui.statusbar.NotificationLockscreenUserManager
+        .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.PreviewInflater;
+
+public class StatusBarRemoteInputCallback implements Callback, Callbacks {
+
+    private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+    private final StatusBarStateController mStatusBarStateController
+            = Dependency.get(StatusBarStateController.class);
+    private final NotificationLockscreenUserManager mLockscreenUserManager
+            = Dependency.get(NotificationLockscreenUserManager.class);
+    private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
+    private final Context mContext;
+    private View mPendingWorkRemoteInputView;
+    private final StatusBarStateController.StateListener mStateListener = this::setStatusBarState;
+    private View mPendingRemoteInputView;
+    private final ShadeController mShadeController = Dependency.get(ShadeController.class);
+    private KeyguardManager mKeyguardManager;
+    private final CommandQueue mCommandQueue;
+    private int mDisabled2;
+    protected BroadcastReceiver mChallengeReceiver = new ChallengeReceiver();
+
+    public StatusBarRemoteInputCallback(Context context) {
+        mContext = context;
+        mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
+                new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
+        mStatusBarStateController.addListener(mStateListener);
+        mKeyguardManager = context.getSystemService(KeyguardManager.class);
+        mCommandQueue = getComponent(context, CommandQueue.class);
+        mCommandQueue.addCallbacks(this);
+    }
+
+    private void setStatusBarState(int state) {
+        if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
+            if (!mStatusBarStateController.isKeyguardRequested()) {
+                if (mPendingRemoteInputView != null
+                        && mPendingRemoteInputView.isAttachedToWindow()) {
+                    mPendingRemoteInputView.post(mPendingRemoteInputView::callOnClick);
+                }
+                mPendingRemoteInputView = null;
+            }
+        }
+    }
+
+    @Override
+    public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
+        mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        mShadeController.showBouncer(true /* scrimmed */);
+        mPendingRemoteInputView = clicked;
+    }
+
+    protected void onWorkChallengeChanged() {
+        if (mPendingWorkRemoteInputView != null
+                && !mLockscreenUserManager.isAnyProfilePublicMode()) {
+            // Expand notification panel and the notification row, then click on remote input view
+            final Runnable clickPendingViewRunnable = () -> {
+                final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+                if (pendingWorkRemoteInputView == null) {
+                    return;
+                }
+
+                // Climb up the hierarchy until we get to the container for this row.
+                ViewParent p = pendingWorkRemoteInputView.getParent();
+                while (!(p instanceof ExpandableNotificationRow)) {
+                    if (p == null) {
+                        return;
+                    }
+                    p = p.getParent();
+                }
+
+                final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
+                ViewParent viewParent = row.getParent();
+                if (viewParent instanceof NotificationStackScrollLayout) {
+                    final NotificationStackScrollLayout scrollLayout =
+                            (NotificationStackScrollLayout) viewParent;
+                    row.makeActionsVisibile();
+                    row.post(() -> {
+                        final Runnable finishScrollingCallback = () -> {
+                            mPendingWorkRemoteInputView.callOnClick();
+                            mPendingWorkRemoteInputView = null;
+                            scrollLayout.setFinishScrollingCallback(null);
+                        };
+                        if (scrollLayout.scrollTo(row)) {
+                            // It scrolls! So call it when it's finished.
+                            scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
+                        } else {
+                            // It does not scroll, so call it now!
+                            finishScrollingCallback.run();
+                        }
+                    });
+                }
+            };
+            mShadeController.postOnShadeExpanded(clickPendingViewRunnable);
+            mShadeController.instantExpandNotificationsPanel();
+        }
+    }
+
+    @Override
+    public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
+            View clickedView) {
+        if (mKeyguardMonitor.isShowing()) {
+            onLockedRemoteInput(row, clickedView);
+        } else {
+            row.setUserExpanded(true);
+            row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
+        }
+    }
+
+    @Override
+    public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
+            View clicked) {
+        // Collapse notification and show work challenge
+        mCommandQueue.animateCollapsePanels();
+        startWorkChallengeIfNecessary(userId, null, null);
+        // Add pending remote input view after starting work challenge, as starting work challenge
+        // will clear all previous pending review view
+        mPendingWorkRemoteInputView = clicked;
+    }
+
+    protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
+            String notificationKey) {
+        // Clear pending remote view, as we do not want to trigger pending remote input view when
+        // it's called by other code
+        mPendingWorkRemoteInputView = null;
+        // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
+        final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+                null, userId);
+        if (newIntent == null) {
+            return false;
+        }
+        final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+        callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
+        callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
+        callBackIntent.setPackage(mContext.getPackageName());
+
+        PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
+                mContext,
+                0,
+                callBackIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT |
+                        PendingIntent.FLAG_ONE_SHOT |
+                        PendingIntent.FLAG_IMMUTABLE);
+        newIntent.putExtra(
+                Intent.EXTRA_INTENT,
+                callBackPendingIntent.getIntentSender());
+        try {
+            ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
+                    null /*options*/);
+        } catch (RemoteException ex) {
+            // ignore
+        }
+        return true;
+        // End old BaseStatusBar.startWorkChallengeIfNecessary.
+    }
+
+    @Override
+    public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
+        // Skip remote input as doing so will expand the notification shade.
+        return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
+    }
+
+    @Override
+    public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
+            Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
+        final boolean isActivity = pendingIntent.isActivity();
+        if (isActivity) {
+            final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
+                    mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
+            mActivityStarter.dismissKeyguardThenExecute(() -> {
+                try {
+                    ActivityManager.getService().resumeAppSwitches();
+                } catch (RemoteException e) {
+                }
+
+                boolean handled = defaultHandler.handleClick();
+
+                // close the shade if it was open and maybe wait for activity start.
+                return handled && mShadeController.closeShadeIfOpen();
+            }, null, afterKeyguardGone);
+            return true;
+        } else {
+            return defaultHandler.handleClick();
+        }
+    }
+
+    @Override
+    public void disable(int state1, int state2, boolean animate) {
+        mDisabled2 = state2;
+    }
+
+    protected class ChallengeReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+            if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+                if (userId != mLockscreenUserManager.getCurrentUserId()
+                        && mLockscreenUserManager.isCurrentProfile(userId)) {
+                    onWorkChallengeChanged();
+                }
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index 8e32a0b..59bd85e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -27,8 +27,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.os.SystemProperties;
-import android.view.DisplayListCanvas;
+import android.graphics.RecordingCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -122,7 +121,7 @@
     public void draw(Canvas canvas) {
         mSupportHardware = canvas.isHardwareAccelerated();
         if (mSupportHardware) {
-            drawHardware((DisplayListCanvas) canvas);
+            drawHardware((RecordingCanvas) canvas);
         } else {
             drawSoftware(canvas);
         }
@@ -147,7 +146,7 @@
         return getBounds().width() > getBounds().height();
     }
 
-    private void drawHardware(DisplayListCanvas c) {
+    private void drawHardware(RecordingCanvas c) {
         if (mDrawingHardwareGlow) {
             c.drawRoundRect(mLeftProp, mTopProp, mRightProp, mBottomProp, mRxProp, mRyProp,
                     mPaintProp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 7b42dd4..aba2377 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -24,6 +24,7 @@
     boolean isOccluded();
     boolean isKeyguardFadingAway();
     boolean isKeyguardGoingAway();
+    boolean isLaunchTransitionFadingAway();
     long getKeyguardFadingAwayDuration();
     long getKeyguardFadingAwayDelay();
     long calculateGoingToFullShadeDelay();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 10cb09b..5eb0fb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -28,7 +28,7 @@
 public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
         implements KeyguardMonitor {
 
-    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
 
     private final Context mContext;
     private final CurrentUserTracker mUserTracker;
@@ -45,6 +45,7 @@
     private long mKeyguardFadingAwayDelay;
     private long mKeyguardFadingAwayDuration;
     private boolean mKeyguardGoingAway;
+    private boolean mLaunchTransitionFadingAway;
 
     public KeyguardMonitorImpl(Context context) {
         mContext = context;
@@ -123,7 +124,7 @@
 
     private void notifyKeyguardChanged() {
         // Copy the list to allow removal during callback.
-        new ArrayList<Callback>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
+        new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
     }
 
     public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
@@ -165,4 +166,13 @@
     public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
         mKeyguardGoingAway = keyguardGoingAway;
     }
+
+    public void setLaunchTransitionFadingAway(boolean fadingAway) {
+        mLaunchTransitionFadingAway = fadingAway;
+    }
+
+    @Override
+    public boolean isLaunchTransitionFadingAway() {
+        return mLaunchTransitionFadingAway;
+    }
 }
\ No newline at end of file
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 dd03162..aa4782f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -28,7 +28,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ContrastColorUtil;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationData;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
index 3f85c9d..a69fd56 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
@@ -23,6 +23,7 @@
 import android.testing.TestableLooper;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -44,7 +45,7 @@
     @Test
     public void testHasDismissActions() {
         Assert.assertFalse("Action not set yet", mKeyguardHostView.hasDismissActions());
-        mKeyguardHostView.setOnDismissAction(mock(KeyguardHostView.OnDismissAction.class),
+        mKeyguardHostView.setOnDismissAction(mock(OnDismissAction.class),
                 null /* cancelAction */);
         Assert.assertTrue("Action should exist", mKeyguardHostView.hasDismissActions());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index a35ca46..a58bc85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -58,7 +58,6 @@
 
     @Before
     public void SysuiSetup() throws Exception {
-        mContext.setTheme(R.style.Theme_SystemUI);
         SystemUIFactory.createFromConfig(mContext);
 
         mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
index 9d3124e..e811270 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
@@ -25,10 +25,12 @@
 
     public SysuiTestableContext(Context base) {
         super(base);
+        setTheme(R.style.Theme_SystemUI);
     }
 
     public SysuiTestableContext(Context base, LeakCheck check) {
         super(base, check);
+        setTheme(R.style.Theme_SystemUI);
     }
 
     public ArrayMap<Class<?>, Object> getComponents() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java b/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
index 5c83d99..0c8d137 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
@@ -25,6 +25,9 @@
     private final ArraySet<Object> mInstantiatedObjects = new ArraySet<>();
 
     public TestableDependency(Context context) {
+        if (context instanceof SysuiTestableContext) {
+            mComponents = ((SysuiTestableContext) context).getComponents();
+        }
         mContext = context;
         if (SystemUIFactory.getInstance() == null) {
             SystemUIFactory.createFromConfig(context);
@@ -43,6 +46,9 @@
     }
 
     public <T> void injectTestDependency(Class<T> key, T obj) {
+        if (mInstantiatedObjects.contains(key)) {
+            throw new IllegalStateException(key + " was already initialized");
+        }
         mObjs.put(key, obj);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index a02ef98..8ae3cd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -84,7 +84,7 @@
     public void testCollapsePanels() {
         mCommandQueue.animateCollapsePanels();
         waitForIdleSync();
-        verify(mCallbacks).animateCollapsePanels(eq(0));
+        verify(mCallbacks).animateCollapsePanels(eq(0), eq(false));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index da59450..2e280d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -17,26 +17,27 @@
 package com.android.systemui.statusbar;
 
 import static org.junit.Assert.assertFalse;
-import static org.mockito.Mockito.when;
 
 import android.os.Handler;
-import android.os.Looper;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.NotificationInfo;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
+import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -49,25 +50,29 @@
  */
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@Ignore("b/118400112")
 public class NonPhoneDependencyTest extends SysuiTestCase {
     @Mock private NotificationPresenter mPresenter;
     @Mock private NotificationListContainer mListContainer;
     @Mock private NotificationEntryManager.Callback mEntryManagerCallback;
     @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private RemoteInputController.Delegate mDelegate;
-    @Mock private NotificationInfo.CheckSaveListener mCheckSaveListener;
-    @Mock private NotificationGutsManager.OnSettingsClickListener mOnClickListener;
     @Mock private NotificationRemoteInputManager.Callback mRemoteInputManagerCallback;
+    @Mock private CheckSaveListener mCheckSaveListener;
+    @Mock private OnSettingsClickListener mOnSettingsClickListener;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+               new Handler(TestableLooper.get(this).getLooper()));
     }
 
     @Test
+    @Ignore("b/118400112")
     public void testNotificationManagementCodeHasNoDependencyOnStatusBarWindowManager() {
+        mDependency.injectMockDependency(ShadeController.class);
         NotificationEntryManager entryManager = Dependency.get(NotificationEntryManager.class);
         NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class);
         NotificationListener notificationListener = Dependency.get(NotificationListener.class);
@@ -79,24 +84,20 @@
                 Dependency.get(NotificationLockscreenUserManager.class);
         NotificationViewHierarchyManager viewHierarchyManager =
                 Dependency.get(NotificationViewHierarchyManager.class);
-        NotificationGroupManager groupManager = Dependency.get(NotificationGroupManager.class);
-
-        when(mPresenter.getNotificationLockscreenUserManager()).thenReturn(lockscreenUserManager);
-        when(mPresenter.getGroupManager()).thenReturn(groupManager);
-
+        Dependency.get(InitController.class).executePostInitTasks();
         entryManager.setUpWithPresenter(mPresenter, mListContainer, mEntryManagerCallback,
                 mHeadsUpManager);
-        groupManager.setHeadsUpManager(mHeadsUpManager);
-        gutsManager.setUpWithPresenter(mPresenter, mListContainer, mCheckSaveListener,
-                mOnClickListener);
-        notificationLogger.setUpWithEntryManager(entryManager, mListContainer);
-        mediaManager.setUpWithPresenter(mPresenter, entryManager);
-        remoteInputManager.setUpWithPresenter(mPresenter, entryManager, mRemoteInputManagerCallback,
+        gutsManager.setUpWithPresenter(mPresenter, mListContainer,
+                mCheckSaveListener, mOnSettingsClickListener);
+        notificationLogger.setUpWithContainer(mListContainer);
+        mediaManager.setUpWithPresenter(mPresenter);
+        remoteInputManager.setUpWithPresenter(mPresenter, mRemoteInputManagerCallback,
                 mDelegate);
-        lockscreenUserManager.setUpWithPresenter(mPresenter, entryManager);
-        viewHierarchyManager.setUpWithPresenter(mPresenter, entryManager, mListContainer);
-        notificationListener.setUpWithPresenter(mPresenter, entryManager);
+        lockscreenUserManager.setUpWithPresenter(mPresenter);
+        viewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
+        notificationListener.setUpWithPresenter(mPresenter);
 
+        TestableLooper.get(this).processAllMessages();
         assertFalse(mDependency.hasInstantiatedDependency(StatusBarWindowController.class));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 7b0c0a0..63ececb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -32,6 +32,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -44,7 +45,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class NotificationListenerTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
     private static final int TEST_UID = 0;
@@ -66,15 +67,16 @@
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         mDependency.injectTestDependency(NotificationRemoteInputManager.class,
                 mRemoteInputManager);
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+                new Handler(TestableLooper.get(this).getLooper()));
 
-        when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
         when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
 
         mListener = new NotificationListener(mContext);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 new Notification(), UserHandle.CURRENT, null, 0);
 
-        mListener.setUpWithPresenter(mPresenter, mEntryManager);
+        mListener.setUpWithPresenter(mPresenter);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 515c109..f168a49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -40,7 +40,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
-import android.util.Log;
+import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -83,12 +83,12 @@
 
         when(mUserManager.getProfiles(mCurrentUserId)).thenReturn(Lists.newArrayList(
                 new UserInfo(mCurrentUserId, "", 0), new UserInfo(mCurrentUserId + 1, "", 0)));
-        when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
         when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+                Handler.createAsync(Looper.myLooper()));
 
         mLockscreenUserManager = new TestNotificationLockscreenUserManager(mContext);
-        mLockscreenUserManager.setUpWithPresenter(mPresenter, mEntryManager);
-        mLockscreenUserManager.setKeyguardViewManager(mKeyguardViewManager);
+        mLockscreenUserManager.setUpWithPresenter(mPresenter);
     }
 
     @Test
@@ -137,15 +137,6 @@
     }
 
     @Test
-    public void testActionDeviceLockedChangedWithDifferentUserIdCallsOnWorkChallengeChanged() {
-        Intent intent = new Intent()
-                .setAction(ACTION_DEVICE_LOCKED_CHANGED)
-                .putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId + 1);
-        mLockscreenUserManager.getAllUsersReceiverForTest().onReceive(mContext, intent);
-        verify(mPresenter, times(1)).onWorkChallengeChanged();
-    }
-
-    @Test
     public void testActionUserSwitchedCallsOnUserSwitched() {
         Intent intent = new Intent()
                 .setAction(ACTION_USER_SWITCHED)
@@ -161,15 +152,11 @@
         assertTrue(mLockscreenUserManager.isLockscreenPublicMode(mCurrentUserId));
     }
 
-    private class TestNotificationLockscreenUserManager extends NotificationLockscreenUserManager {
+    private class TestNotificationLockscreenUserManager extends NotificationLockscreenUserManagerImpl {
         public TestNotificationLockscreenUserManager(Context context) {
             super(context);
         }
 
-        public BroadcastReceiver getAllUsersReceiverForTest() {
-            return mAllUsersReceiver;
-        }
-
         public BroadcastReceiver getBaseBroadcastReceiverForTest() {
             return mBaseBroadcastReceiver;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 8a59e96..d409e2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -20,6 +20,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 
 import com.android.systemui.statusbar.notification.NotificationData;
@@ -70,8 +71,8 @@
         mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
                 mLockscreenUserManager);
         mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
-
-        when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+                Handler.createAsync(Looper.myLooper()));
 
         mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
@@ -79,7 +80,7 @@
         mEntry = new NotificationData.Entry(mSbn);
         mEntry.row = mRow;
 
-        mRemoteInputManager.setUpWithPresenterForTest(mPresenter, mEntryManager, mCallback,
+        mRemoteInputManager.setUpWithPresenterForTest(mPresenter, mCallback,
                 mDelegate, mController);
         for (NotificationLifetimeExtender extender : mRemoteInputManager.getLifetimeExtenders()) {
             extender.setCallback(
@@ -201,11 +202,10 @@
         }
 
         public void setUpWithPresenterForTest(NotificationPresenter presenter,
-                NotificationEntryManager entryManager,
                 Callback callback,
                 RemoteInputController.Delegate delegate,
                 RemoteInputController controller) {
-            super.setUpWithPresenter(presenter, entryManager, callback, delegate);
+            super.setUpWithPresenter(presenter, callback, delegate);
             mRemoteInputController = controller;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 6b4ccc4..602e613 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -32,6 +32,8 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
+import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.notification.NotificationData;
@@ -42,6 +44,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 
 import com.google.android.collect.Lists;
 
@@ -67,6 +70,7 @@
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationGroupManager mGroupManager;
     @Mock private VisualStabilityManager mVisualStabilityManager;
+    @Mock private ShadeController mShadeController;
 
     private NotificationViewHierarchyManager mViewHierarchyManager;
     private NotificationTestHelper mHelper = new NotificationTestHelper(mContext);;
@@ -79,11 +83,13 @@
                 mLockscreenUserManager);
         mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
+        mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
         when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
 
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext);
-        mViewHierarchyManager.setUpWithPresenter(mPresenter, mEntryManager, mListContainer);
+        Dependency.get(InitController.class).executePostInitTasks();
+        mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
     }
 
     private NotificationData.Entry createEntry() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 17daaac..1d977d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -80,8 +80,7 @@
                 mSmartReplyController);
 
         mRemoteInputManager = new NotificationRemoteInputManager(mContext);
-        mRemoteInputManager.setUpWithPresenter(mPresenter, mNotificationEntryManager, mCallback,
-                mDelegate);
+        mRemoteInputManager.setUpWithPresenter(mPresenter, mCallback, mDelegate);
         mNotification = new Notification.Builder(mContext, "")
                 .setSmallIcon(R.drawable.ic_person)
                 .setContentTitle("Title")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AppOpsListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AppOpsListenerTest.java
index 78be783..b405a5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AppOpsListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AppOpsListenerTest.java
@@ -18,7 +18,6 @@
 
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
 import android.os.Handler;
@@ -27,6 +26,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -59,14 +59,15 @@
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
         getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager);
-        when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+                Handler.createAsync(Looper.myLooper()));
 
         mListener = new AppOpsListener(mContext);
     }
 
     @Test
     public void testOnlyListenForFewOps() {
-        mListener.setUpWithPresenter(mPresenter, mEntryManager);
+        mListener.setUpWithPresenter(mPresenter);
 
         verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsListener.OPS, mListener);
     }
@@ -79,7 +80,7 @@
 
     @Test
     public void testInformEntryMgrOnAppOpsChange() {
-        mListener.setUpWithPresenter(mPresenter, mEntryManager);
+        mListener.setUpWithPresenter(mPresenter);
         mListener.onOpActiveChanged(
                 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
         TestableLooper.get(this).processAllMessages();
@@ -89,7 +90,7 @@
 
     @Test
     public void testInformFscOnAppOpsChange() {
-        mListener.setUpWithPresenter(mPresenter, mEntryManager);
+        mListener.setUpWithPresenter(mPresenter);
         mListener.onOpActiveChanged(
                 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
         TestableLooper.get(this).processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index de5a8a0..459dc5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -55,13 +55,16 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.ArraySet;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -87,7 +90,7 @@
     @Mock
     ForegroundServiceController mFsc;
     @Mock
-    NotificationData.Environment mEnvironment;
+    NotificationData.KeyguardEnvironment mEnvironment;
 
     private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
     private NotificationData mNotificationData;
@@ -108,10 +111,14 @@
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
 
         mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
-        when(mEnvironment.getGroupManager()).thenReturn(new NotificationGroupManager());
+        mDependency.injectTestDependency(NotificationGroupManager.class,
+                new NotificationGroupManager());
+        mDependency.injectMockDependency(ShadeController.class);
+        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-        mNotificationData = new TestableNotificationData(mEnvironment);
+        mNotificationData = new TestableNotificationData();
+        Dependency.get(InitController.class).executePostInitTasks();
         mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
         mRow = new NotificationTestHelper(getContext()).createRow();
     }
@@ -298,11 +305,11 @@
                 mRow.getEntry().notification)).thenReturn(false);
         when(mEnvironment.isNotificationForCurrentProfiles(
                 row2.getEntry().notification)).thenReturn(true);
-        ArrayList<NotificationData.Entry> reuslt =
+        ArrayList<NotificationData.Entry> result =
                 mNotificationData.getNotificationsForCurrentUser();
 
-        assertEquals(reuslt.size(), 1);
-        junit.framework.Assert.assertEquals(reuslt.get(0), row2.getEntry());
+        assertEquals(result.size(), 1);
+        junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
     }
 
     @Test
@@ -416,8 +423,8 @@
     }
 
     private class TestableNotificationData extends NotificationData {
-        public TestableNotificationData(Environment environment) {
-            super(environment);
+        public TestableNotificationData() {
+            super();
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index f01ae7a..fb4ecd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -54,7 +54,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
@@ -66,12 +68,14 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -97,6 +101,7 @@
     private static final int TEST_UID = 0;
 
     @Mock private NotificationPresenter mPresenter;
+    @Mock private KeyguardEnvironment mEnvironment;
     @Mock private ExpandableNotificationRow mRow;
     @Mock private NotificationListContainer mListContainer;
     @Mock private NotificationEntryManager.Callback mCallback;
@@ -190,6 +195,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectTestDependency(ForegroundServiceController.class,
                 mForegroundServiceController);
         mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
@@ -204,12 +210,12 @@
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
+        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
 
         mCountDownLatch = new CountDownLatch(1);
 
-        when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
-        when(mPresenter.getNotificationLockscreenUserManager()).thenReturn(mLockscreenUserManager);
-        when(mPresenter.getGroupManager()).thenReturn(mGroupManager);
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+                Handler.createAsync(Looper.myLooper()));
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
         when(mListContainer.getViewParentForNotification(any())).thenReturn(
                 new FrameLayout(mContext));
@@ -224,6 +230,7 @@
         mEntry.expandedIcon = mock(StatusBarIconView.class);
 
         mEntryManager = new TestableNotificationEntryManager(mContext, mBarService);
+        Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mCallback, mHeadsUpManager);
 
         setUserSentiment(mEntry.key, NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
@@ -421,8 +428,9 @@
 
     @Test
     public void testUpdateNotificationRanking() {
-        when(mPresenter.isDeviceProvisioned()).thenReturn(true);
-        when(mPresenter.isNotificationForCurrentProfiles(any())).thenReturn(true);
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+        when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
+        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
 
         mEntry.row = mRow;
         mEntry.setInflationTask(mAsyncInflationTask);
@@ -437,8 +445,8 @@
 
     @Test
     public void testUpdateNotificationRanking_noChange() {
-        when(mPresenter.isDeviceProvisioned()).thenReturn(true);
-        when(mPresenter.isNotificationForCurrentProfiles(any())).thenReturn(true);
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
 
         mEntry.row = mRow;
         mEntryManager.getNotificationData().add(mEntry);
@@ -451,8 +459,8 @@
 
     @Test
     public void testUpdateNotificationRanking_rowNotInflatedYet() {
-        when(mPresenter.isDeviceProvisioned()).thenReturn(true);
-        when(mPresenter.isNotificationForCurrentProfiles(any())).thenReturn(true);
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
 
         mEntry.row = null;
         mEntryManager.getNotificationData().add(mEntry);
@@ -466,8 +474,8 @@
 
     @Test
     public void testUpdateNotificationRanking_pendingNotification() {
-        when(mPresenter.isDeviceProvisioned()).thenReturn(true);
-        when(mPresenter.isNotificationForCurrentProfiles(any())).thenReturn(true);
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
 
         mEntry.row = null;
         mEntryManager.mPendingNotifications.put(mEntry.key, mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index ca62c3b..1c7a8e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -92,7 +92,7 @@
         mEntry.row = mRow;
 
         mLogger = new TestableNotificationLogger(mBarService);
-        mLogger.setUpWithEntryManager(mEntryManager, mListContainer);
+        mLogger.setUpWithContainer(mListContainer);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index cfc7526..bf8eb62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -20,10 +20,10 @@
 
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_ALL;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -40,7 +40,6 @@
 import android.app.NotificationChannel;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.ArraySet;
 import android.view.NotificationHeaderView;
@@ -54,6 +53,7 @@
 
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -126,7 +126,8 @@
 
     @Test
     public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception {
-        ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow());
+        ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow(
+                FLAG_CONTENT_VIEW_ALL));
         row.setSensitive(true, true);
         row.setHideSensitive(true, false, 0, 0);
         verify(row).updateShelfIconColor();
@@ -139,7 +140,10 @@
         verify(row).updateShelfIconColor();
     }
 
+    // TODO: Ignoring as a temporary workaround until heads up views can be safely freed.
+    // See http://b/117933032
     @Test
+    @Ignore
     public void testFreeContentViewWhenSafe() throws Exception {
         ExpandableNotificationRow row = mNotificationTestHelper.createRow(FLAG_CONTENT_VIEW_ALL);
 
@@ -149,6 +153,26 @@
     }
 
     @Test
+    public void setNeedsRedactionSetsInflationFlag() throws Exception {
+        ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+        row.setNeedsRedaction(true);
+
+        assertTrue(row.getNotificationInflater().isInflationFlagSet(FLAG_CONTENT_VIEW_PUBLIC));
+    }
+
+    @Test
+    public void setNeedsRedactionFreesViewWhenFalse() throws Exception {
+        ExpandableNotificationRow row = mNotificationTestHelper.createRow(FLAG_CONTENT_VIEW_ALL);
+        row.setNeedsRedaction(true);
+        row.getPublicLayout().setVisibility(View.GONE);
+
+        row.setNeedsRedaction(false);
+
+        assertNull(row.getPublicLayout().getContractedChild());
+    }
+
+    @Test
     public void testAboveShelfChangedListenerCalled() throws Exception {
         ExpandableNotificationRow row = mNotificationTestHelper.createRow();
         AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 8edbf17..ee35449 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -61,7 +61,9 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -93,11 +95,14 @@
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotificationStackScrollLayout mStackScroller;
     @Mock private NotificationInfo.CheckSaveListener mCheckSaveListener;
-    @Mock private NotificationGutsManager.OnSettingsClickListener mOnSettingsClickListener;
+    @Mock private OnSettingsClickListener mOnSettingsClickListener;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
 
     @Before
     public void setUp() {
         mTestableLooper = TestableLooper.get(this);
+        mDependency.injectTestDependency(DeviceProvisionedController.class,
+                mDeviceProvisionedController);
         mHandler = Handler.createAsync(mTestableLooper.getLooper());
 
         mHelper = new NotificationTestHelper(mContext);
@@ -330,7 +335,7 @@
         row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
-        when(mPresenter.isDeviceProvisioned()).thenReturn(true);
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
 
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
index 150d933..fdb66cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
@@ -16,9 +16,11 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_ALL;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_EXPANDED;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -45,8 +47,8 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationData;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -115,7 +117,10 @@
         verify(mRow).onNotificationUpdated();
     }
 
+    // TODO: Ignoring as a temporary workaround until ambient views can be safely freed.
+    // See http://b/117894786
     @Test
+    @Ignore
     public void testInflationOnlyInflatesSetFlags() throws Exception {
         mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP,
                 true /* shouldInflate */);
@@ -191,6 +196,19 @@
         assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
     }
 
+    @Test
+    public void testUpdateNeedsRedactionReinflatesChangedContentViews() {
+        mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, true);
+        mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, true);
+        mNotificationInflater.updateNeedsRedaction(true);
+
+        NotificationInflater.AsyncInflationTask asyncInflationTask =
+                (NotificationInflater.AsyncInflationTask) mRow.getEntry().getRunningTask();
+        assertEquals(FLAG_CONTENT_VIEW_AMBIENT | FLAG_CONTENT_VIEW_PUBLIC,
+                asyncInflationTask.getReInflateFlags());
+        asyncInflationTask.abort();
+    }
+
     /* Cancelling requires us to be on the UI thread otherwise we might have a race */
     @Test
     public void testSupersedesExistingTask() {
@@ -205,7 +223,7 @@
         NotificationInflater.AsyncInflationTask asyncInflationTask =
                 (NotificationInflater.AsyncInflationTask) runningTask;
         assertEquals("Successive inflations don't inherit the previous flags!",
-                asyncInflationTask.getReInflateFlags(), FLAG_CONTENT_VIEW_ALL);
+                FLAG_CONTENT_VIEW_ALL, asyncInflationTask.getReInflateFlags());
         runningTask.abort();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index f8b2436..d2fe82f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -17,6 +17,8 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -40,30 +42,31 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.ExpandHelper;
+import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.FooterView;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager;
 
-import java.util.ArrayList;
-
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -74,6 +77,8 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
+
 /**
  * Tests for {@link NotificationStackScrollLayout}.
  */
@@ -108,6 +113,7 @@
         mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
         mDependency.injectTestDependency(NotificationRemoteInputManager.class,
                 mRemoteInputManager);
+        mDependency.injectMockDependency(ShadeController.class);
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
 
         IPowerManager powerManagerService = mock(IPowerManager.class);
@@ -116,11 +122,13 @@
 
         mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager,
                 mContext);
+        mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
+        Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, mHeadsUpManager,
                 mNotificationData);
-        mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
 
-        NotificationShelf notificationShelf = spy(new NotificationShelf(getContext(), null));
+
+        NotificationShelf notificationShelf = mock(NotificationShelf.class);
         mStackScroller = spy(new NotificationStackScrollLayout(getContext()));
         mStackScroller.setShelf(notificationShelf);
         mStackScroller.setStatusBar(mBar);
@@ -147,7 +155,7 @@
         when(mBarState.getState()).thenReturn(StatusBarState.SHADE);
         mStackScroller.setDimmed(true /* dimmed */, false /* animate */);
         mStackScroller.setDimmed(true /* dimmed */, true /* animate */);
-        Assert.assertFalse(mStackScroller.isDimmed());
+        assertFalse(mStackScroller.isDimmed());
     }
 
     @Test
@@ -246,7 +254,7 @@
         assertEquals(0, mNotificationData.getActiveNotifications().size());
 
         mStackScroller.updateFooter();
-        verify(mStackScroller).updateFooterView(false, false);
+        verify(mStackScroller, atLeastOnce()).updateFooterView(false, false);
     }
 
     @Test
@@ -287,7 +295,8 @@
         setBarStateForTest(StatusBarState.SHADE);
         ArrayList<Entry> entries = new ArrayList<>();
         entries.add(mock(Entry.class));
-        when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+        when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
+        assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
 
         mStackScroller.updateFooter();
         verify(mStackScroller).updateFooterView(true, false);
@@ -348,9 +357,8 @@
     }
 
     private void setBarStateForTest(int state) {
-        ArgumentCaptor<StatusBarStateController.StateListener> captor =
-                ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
-        verify(mBarState, atLeastOnce()).addListener(captor.capture());
-        captor.getValue().onStateChanged(state);
+        // Can't inject this through the listener or we end up on the actual implementation
+        // rather than the mock because the spy just coppied the anonymous inner /shruggie.
+        mStackScroller.setStatusBarState(state);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
new file mode 100644
index 0000000..96f1976
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
@@ -0,0 +1,47 @@
+package com.android.systemui.statusbar.phone
+
+import android.support.test.filters.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.KeyguardIndicationController
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardBottomAreaTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var mStatusBar: StatusBar
+    @Mock
+    private lateinit var mKeyguardIndicationController: KeyguardIndicationController
+    private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
+                R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
+        mKeyguardBottomArea.setStatusBar(mStatusBar)
+        mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController)
+    }
+
+    @Test
+    fun initFrom_doesntCrash() {
+        val other = LayoutInflater.from(mContext).inflate(
+                R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
+
+        other.initFrom(mKeyguardBottomArea)
+        other.launchVoiceAssist()
+        other.onLongClick(null)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 020682b6..7f8668f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -238,7 +239,7 @@
 
     @Test
     public void testShowOnDismissAction_showsBouncer() {
-        final KeyguardHostView.OnDismissAction dismissAction = () -> false;
+        final OnDismissAction dismissAction = () -> false;
         final Runnable cancelAction = () -> {};
         mBouncer.showWithDismissAction(dismissAction, cancelAction);
         verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java
new file mode 100644
index 0000000..be26d91
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.TestableDependency;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.statusbar.policy.RotationLockController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+/** atest NavigationBarRotationContextTest */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NavigationBarRotationContextTest extends SysuiTestCase {
+    static final int RES_UNDEF = 0;
+    static final int DEFAULT_ROTATE = 0;
+
+    @Rule
+    public final SysuiTestableContext mContext = new SysuiTestableContext(
+            InstrumentationRegistry.getContext(), getLeakCheck());
+    private final TestableDependency mDependency = new TestableDependency(mContext);
+    private RotationContextButton mButton;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDependency.injectMockDependency(RotationLockController.class);
+
+        final View view = new View(mContext);
+        mButton = spy(new RotationContextButton(RES_UNDEF, RES_UNDEF, mContext, RES_UNDEF));
+        final KeyButtonDrawable kbd = mock(KeyButtonDrawable.class);
+        doReturn(view).when(mButton).getCurrentView();
+        doReturn(kbd).when(mButton).getNewDrawable();
+    }
+
+    @Test
+    public void testOnInvalidRotationProposal() {
+        mButton.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1, false /* isValid */);
+        verify(mButton, times(1)).setRotateSuggestionButtonState(false /* visible */);
+    }
+
+    @Test
+    public void testOnSameRotationProposal() {
+        mButton.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE, true /* isValid */);
+        verify(mButton, times(1)).setRotateSuggestionButtonState(false /* visible */);
+    }
+
+    @Test
+    public void testOnRotationProposalShowButtonShowNav() {
+        // No navigation bar should not call to set visibility state
+        mButton.onNavigationBarWindowVisibilityChange(false /* showing */);
+        verify(mButton, times(0)).setRotateSuggestionButtonState(false /* visible */);
+        verify(mButton, times(0)).setRotateSuggestionButtonState(true /* visible */);
+
+        // No navigation bar with rotation change should not call to set visibility state
+        mButton.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1, true /* isValid */);
+        verify(mButton, times(0)).setRotateSuggestionButtonState(false /* visible */);
+        verify(mButton, times(0)).setRotateSuggestionButtonState(true /* visible */);
+
+        // Since rotation has changed rotation should be pending, show mButton when showing nav bar
+        mButton.onNavigationBarWindowVisibilityChange(true /* showing */);
+        verify(mButton, times(1)).setRotateSuggestionButtonState(true /* visible */);
+    }
+
+    @Test
+    public void testOnRotationProposalShowButton() {
+        // Navigation bar being visible should not call to set visibility state
+        mButton.onNavigationBarWindowVisibilityChange(true /* showing */);
+        verify(mButton, times(0)).setRotateSuggestionButtonState(false /* visible */);
+        verify(mButton, times(0)).setRotateSuggestionButtonState(true /* visible */);
+
+        // Navigation bar is visible and rotation requested
+        mButton.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1, true /* isValid */);
+        verify(mButton, times(1)).setRotateSuggestionButtonState(true /* visible */);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index be4560b..93dedfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -31,10 +31,10 @@
 import android.view.ViewGroup;
 
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -78,7 +78,7 @@
 
     @Test
     public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
-        KeyguardHostView.OnDismissAction action = () -> false;
+        OnDismissAction action = () -> false;
         Runnable cancelAction = () -> {};
         mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
                 false /* afterKeyguardGone */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
new file mode 100644
index 0000000..24baa7d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+
+import android.app.Notification;
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.metrics.LogMaker;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.support.test.metricshelper.MetricsAsserts;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.ViewGroup;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class StatusBarNotificationPresenterTest extends SysuiTestCase {
+
+
+    private StatusBarNotificationPresenter mStatusBar;
+    private CommandQueue mCommandQueue;
+    private FakeMetricsLogger mMetricsLogger;
+    private ShadeController mShadeController = mock(ShadeController.class);
+
+    @Before
+    public void setup() {
+        mMetricsLogger = new FakeMetricsLogger();
+        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+        mCommandQueue = new CommandQueue();
+        mContext.putComponent(CommandQueue.class, mCommandQueue);
+        mDependency.injectTestDependency(ShadeController.class, mShadeController);
+
+        mStatusBar = new StatusBarNotificationPresenter(mContext,
+                mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
+                mock(StatusBarWindowView.class), mock(NotificationListContainerViewGroup.class),
+                mock(DozeScrimController.class), mock(ScrimController.class),
+                mock(ActivityLaunchAnimator.Callback.class));
+    }
+
+    @Test
+    public void testHeadsUp_disabledStatusBar() {
+        Notification n = new Notification.Builder(getContext(), "a").build();
+        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+                UserHandle.of(0), null, 0);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        mCommandQueue.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
+        TestableLooper.get(this).processAllMessages();
+
+        assertFalse("The panel shouldn't allow heads up while disabled",
+                mStatusBar.canHeadsUp(entry, sbn));
+    }
+
+    @Test
+    public void testHeadsUp_disabledNotificationShade() {
+        Notification n = new Notification.Builder(getContext(), "a").build();
+        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+                UserHandle.of(0), null, 0);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        mCommandQueue.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
+        TestableLooper.get(this).processAllMessages();
+
+        assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
+                mStatusBar.canHeadsUp(entry, sbn));
+    }
+
+    @Test
+    public void onActivatedMetrics() {
+        ActivatableNotificationView view =  mock(ActivatableNotificationView.class);
+        mStatusBar.onActivated(view);
+
+        MetricsAsserts.assertHasLog("missing lockscreen note tap log",
+                mMetricsLogger.getLogs(),
+                new LogMaker(MetricsEvent.ACTION_LS_NOTE)
+                        .setType(MetricsEvent.TYPE_ACTION));
+    }
+
+    // We need this because mockito doesn't know how to construct a mock that extends ViewGroup
+    // and implements NotificationListContainer without it because of classloader issues.
+    private abstract static class NotificationListContainerViewGroup extends ViewGroup
+            implements NotificationListContainer {
+
+        public NotificationListContainerViewGroup(Context context) {
+            super(context);
+        }
+    }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
new file mode 100644
index 0000000..f28757f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
+    @Mock private NotificationPresenter mPresenter;
+    @Mock private UserManager mUserManager;
+
+    // Dependency mocks:
+    @Mock private NotificationEntryManager mEntryManager;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+    @Mock private ShadeController mShadeController;
+    @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+
+    private int mCurrentUserId = 0;
+    private StatusBarRemoteInputCallback mRemoteInputCallback;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
+        mDependency.injectTestDependency(DeviceProvisionedController.class,
+                mDeviceProvisionedController);
+        mDependency.injectTestDependency(ShadeController.class, mShadeController);
+        mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
+                mNotificationLockscreenUserManager);
+        mDependency.putComponent(CommandQueue.class, mock(CommandQueue.class));
+
+        mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext));
+        mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
+    }
+
+    @Test
+    public void testActionDeviceLockedChangedWithDifferentUserIdCallsOnWorkChallengeChanged() {
+        when(mNotificationLockscreenUserManager.getCurrentUserId()).thenReturn(mCurrentUserId);
+        when(mNotificationLockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(true);
+        Intent intent = new Intent()
+                .setAction(ACTION_DEVICE_LOCKED_CHANGED)
+                .putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId + 1);
+        mRemoteInputCallback.mChallengeReceiver.onReceive(mContext, intent);
+        verify(mRemoteInputCallback, times(1)).onWorkChallengeChanged();
+    }
+
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index da93327..939245f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -18,9 +18,7 @@
 
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
-import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.fail;
 
@@ -64,42 +62,41 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.FakeMetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
-import com.android.systemui.statusbar.notification.AppOpsListener;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AppOpsListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -137,18 +134,21 @@
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
     @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+    @Mock private NotificationPresenter mNotificationPresenter;
+    @Mock private NotificationEntryManager.Callback mCallback;
 
     private TestableStatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
     private PowerManager mPowerManager;
     private TestableNotificationEntryManager mEntryManager;
     private NotificationLogger mNotificationLogger;
+    private CommandQueue mCommandQueue;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(AssistManager.class);
-        mDependency.injectMockDependency(DeviceProvisionedController.class);
         mDependency.injectMockDependency(NotificationGutsManager.class);
         mDependency.injectMockDependency(NotificationMediaManager.class);
         mDependency.injectMockDependency(ForegroundServiceController.class);
@@ -159,6 +159,8 @@
         mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
         mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class));
         mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
+        mDependency.injectTestDependency(DeviceProvisionedController.class,
+                mDeviceProvisionedController);
 
         mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -172,9 +174,9 @@
         mPowerManager = new PowerManager(mContext, powerManagerService,
                 Handler.createAsync(Looper.myLooper()));
 
-        CommandQueue commandQueue = mock(CommandQueue.class);
-        when(commandQueue.asBinder()).thenReturn(new Binder());
-        mContext.putComponent(CommandQueue.class, commandQueue);
+        mCommandQueue = mock(CommandQueue.class);
+        when(mCommandQueue.asBinder()).thenReturn(new Binder());
+        mContext.putComponent(CommandQueue.class, mCommandQueue);
 
         mContext.setTheme(R.style.Theme_SystemUI_Light);
 
@@ -202,17 +204,19 @@
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
                 mEntryManager, mScrimController, mBiometricUnlockController,
-                mock(ActivityLaunchAnimator.class), mKeyguardViewMediator,
-                mRemoteInputManager, mock(NotificationGroupManager.class),
+                mKeyguardViewMediator, mRemoteInputManager, mock(NotificationGroupManager.class),
                 mock(FalsingManager.class), mock(StatusBarWindowController.class),
                 mock(NotificationIconAreaController.class), mock(DozeScrimController.class),
                 mock(NotificationShelf.class), mLockscreenUserManager,
-                mock(CommandQueue.class));
+                mCommandQueue,
+                mNotificationPresenter);
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
-        mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
-                mNotificationData);
-        mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller);
+        mStatusBar.putComponent(StatusBar.class, mStatusBar);
+        Dependency.get(InitController.class).executePostInitTasks();
+        mEntryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller,
+                mCallback, mHeadsUpManager, mNotificationData);
+        mNotificationLogger.setUpWithContainer(mStackScroller);
 
         TestableLooper.get(this).setMessageHandler(m -> {
             if (m.getCallback() == mStatusBar.mNotificationLogger.getVisibilityReporter()) {
@@ -347,17 +351,6 @@
     }
 
     @Test
-    public void onActivatedMetrics() {
-        ActivatableNotificationView view =  mock(ActivatableNotificationView.class);
-        mStatusBar.onActivated(view);
-
-        MetricsAsserts.assertHasLog("missing lockscreen note tap log",
-                mMetricsLogger.getLogs(),
-                new LogMaker(MetricsEvent.ACTION_LS_NOTE)
-                        .setType(MetricsEvent.TYPE_ACTION));
-    }
-
-    @Test
     public void testShouldHeadsUp_nonSuppressedGroupSummary() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
@@ -365,6 +358,7 @@
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+        when(mCallback.canHeadsUp(any(), any())).thenReturn(true);
 
         Notification n = new Notification.Builder(getContext(), "a")
                 .setGroup("a")
@@ -386,6 +380,7 @@
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+        when(mCallback.canHeadsUp(any(), any())).thenReturn(true);
 
         Notification n = new Notification.Builder(getContext(), "a")
                 .setGroup("a")
@@ -406,6 +401,7 @@
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+        when(mCallback.canHeadsUp(any(), any())).thenReturn(true);
 
         when(mNotificationData.shouldSuppressPeek(any())).thenReturn(true);
 
@@ -424,6 +420,7 @@
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+        when(mCallback.canHeadsUp(any(), any())).thenReturn(true);
 
         when(mNotificationData.shouldSuppressPeek(any())).thenReturn(false);
 
@@ -436,30 +433,6 @@
     }
 
     @Test
-    public void testHeadsUp_disabledStatusBar() {
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
-                UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
-        mStatusBar.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
-
-        assertFalse("The panel shouldn't allow heads up while disabled",
-                mStatusBar.canHeadsUp(entry, sbn));
-    }
-
-    @Test
-    public void testHeadsUp_disabledNotificationShade() {
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
-                UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
-        mStatusBar.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
-
-        assertFalse("The panel shouldn't allow heads up while notification shade disabled",
-                mStatusBar.canHeadsUp(entry, sbn));
-    }
-
-    @Test
     public void testLogHidden() {
         try {
             mStatusBar.handleVisibleToUserChanged(false);
@@ -473,10 +446,11 @@
 
     @Test
     public void testPanelOpenForHeadsUp() {
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
         when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
         when(mNotificationList.size()).thenReturn(5);
-        when(mNotificationPanelView.isFullyCollapsed()).thenReturn(true);
+        when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true);
         mStatusBar.setBarStateForTest(StatusBarState.SHADE);
 
         try {
@@ -495,7 +469,7 @@
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
         when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
         when(mNotificationList.size()).thenReturn(5);
-        when(mNotificationPanelView.isFullyCollapsed()).thenReturn(false);
+        when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
         mStatusBar.setBarStateForTest(StatusBarState.SHADE);
 
         try {
@@ -514,7 +488,7 @@
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
         when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
         when(mNotificationList.size()).thenReturn(5);
-        when(mNotificationPanelView.isFullyCollapsed()).thenReturn(false);
+        when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
 
         try {
@@ -532,8 +506,9 @@
     public void testDisableExpandStatusBar() {
         mStatusBar.setBarStateForTest(StatusBarState.SHADE);
         mStatusBar.setUserSetupForTest(true);
-        when(mStatusBar.isDeviceProvisioned()).thenReturn(true);
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
 
+        when(mCommandQueue.panelsEnabled()).thenReturn(false);
         mStatusBar.disable(StatusBarManager.DISABLE_NONE,
                 StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
         verify(mNotificationPanelView).setQsExpansionEnabled(false);
@@ -542,6 +517,7 @@
         mStatusBar.animateExpandSettingsPanel(null);
         verify(mNotificationPanelView, never()).expand(anyBoolean());
 
+        when(mCommandQueue.panelsEnabled()).thenReturn(true);
         mStatusBar.disable(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE, false);
         verify(mNotificationPanelView).setQsExpansionEnabled(true);
         mStatusBar.animateExpandNotificationsPanel();
@@ -627,7 +603,7 @@
                 NotificationViewHierarchyManager viewHierarchyManager,
                 TestableNotificationEntryManager entryManager, ScrimController scrimController,
                 BiometricUnlockController biometricUnlockController,
-                ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator,
+                KeyguardViewMediator keyguardViewMediator,
                 NotificationRemoteInputManager notificationRemoteInputManager,
                 NotificationGroupManager notificationGroupManager,
                 FalsingManager falsingManager,
@@ -636,7 +612,8 @@
                 DozeScrimController dozeScrimController,
                 NotificationShelf notificationShelf,
                 NotificationLockscreenUserManager notificationLockscreenUserManager,
-                CommandQueue commandQueue) {
+                CommandQueue commandQueue,
+                NotificationPresenter notificationPresenter) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -653,7 +630,6 @@
             mEntryManager = entryManager;
             mScrimController = scrimController;
             mBiometricUnlockController = biometricUnlockController;
-            mActivityLaunchAnimator = launchAnimator;
             mKeyguardViewMediator = keyguardViewMediator;
             mRemoteInputManager = notificationRemoteInputManager;
             mGroupManager = notificationGroupManager;
@@ -664,6 +640,7 @@
             mNotificationShelf = notificationShelf;
             mLockscreenUserManager = notificationLockscreenUserManager;
             mCommandQueue = commandQueue;
+            mPresenter = notificationPresenter;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 01e6307..4534ebe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -41,7 +41,7 @@
 import android.widget.Button;
 import android.widget.LinearLayout;
 
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationData;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
index 51b86c2..95c7a4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
@@ -62,6 +62,11 @@
     }
 
     @Override
+    public boolean isLaunchTransitionFadingAway() {
+        return false;
+    }
+
+    @Override
     public long getKeyguardFadingAwayDuration() {
         return 0;
     }
diff --git a/services/art-profile b/services/art-profile
index 4168a3f..742ca1c 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -2082,6 +2082,22 @@
 HPLcom/android/server/usage/StorageStatsService;->queryStatsForUid(Ljava/lang/String;ILjava/lang/String;)Landroid/app/usage/StorageStats;
 HPLcom/android/server/usage/UnixCalendar;->getTimeInMillis()J
 HPLcom/android/server/usage/UsageStatsDatabase$CheckinAction;->checkin(Lcom/android/server/usage/IntervalStats;)Z
+HPLcom/android/server/usage/UsageStatsProto;->readStringPool(Landroid/util/proto/ProtoInputStream;)Ljava/util/List;
+HPLcom/android/server/usage/UsageStatsProto;->loadUsageStats(Landroid/util/proto/ProtoInputStream;Lcom/android/server/usage/IntervalStats;Ljava/util/List;)V
+HPLcom/android/server/usage/UsageStatsProto;->loadCountAndTime(Landroid/util/proto/ProtoInputStream;JLcom/android/server/usage/IntervalStats;$EventTracker)V
+HPLcom/android/server/usage/UsageStatsProto;->loadChooserCounts(Landroid/util/proto/ProtoInputStream;Landroid/app/usage/UsageStats;)V
+HPLcom/android/server/usage/UsageStatsProto;->loadCountsForAction(Landroid/util/proto/ProtoInputStream;Landroid/util/ArrayMap;)V
+HPLcom/android/server/usage/UsageStatsProto;->loadConfigStats(Landroid/util/proto/ProtoInputStream;JLcom/android/server/usage/IntervalStats;)V
+HPLcom/android/server/usage/UsageStatsProto;->loadEvent(Landroid/util/proto/ProtoInputStream;JLcom/android/server/usage/IntervalStats;Ljava/util/List;)V
+HPLcom/android/server/usage/UsageStatsProto;->writeStringPool(Landroid/util/proto/ProtoOutputStream;Lcom/android/server/usage/IntervalStats;)V
+HPLcom/android/server/usage/UsageStatsProto;->writeUsageStats(Landroid/util/proto/ProtoOutputStream;JLcom/android/server/usage/IntervalStats;Landroid/app/usage/UsageStats;)V
+HPLcom/android/server/usage/UsageStatsProto;->writeCountAndTime(Landroid/util/proto/ProtoOutputStream;JIJ)V
+HPLcom/android/server/usage/UsageStatsProto;->writeChooserCounts(Landroid/util/proto/ProtoOutputStream;Landroid/app/usage/UsageStats;)V
+HPLcom/android/server/usage/UsageStatsProto;->writeCountsForAction(Landroid/util/proto/ProtoOutputStream;Landroid/util/ArrayMap;)V
+HPLcom/android/server/usage/UsageStatsProto;->writeConfigStats(Landroid/util/proto/ProtoOutputStream;JLcom/android/server/usage/IntervalStats;Landroid/app/usage/ConfigurationStats;Z)V
+HPLcom/android/server/usage/UsageStatsProto;->writeEvent(Landroid/util/proto/ProtoOutputStream;JLcom/android/server/usage/IntervalStats;Landroid/app/usage/UsageEvents$Event;)V
+HPLcom/android/server/usage/UsageStatsProto;->read(Ljava/io/InputStream;Lcom/android/server/usage/IntervalStats;)V
+HPLcom/android/server/usage/UsageStatsProto;->write(Ljava/io/OutputStream;Lcom/android/server/usage/IntervalStats;)V
 HPLcom/android/server/usage/UsageStatsService$2;->onUidStateChanged(IIJ)V
 HPLcom/android/server/usage/UsageStatsService$BinderService;->hasPermission(Ljava/lang/String;)Z
 HPLcom/android/server/usage/UsageStatsService$BinderService;->isAppInactive(Ljava/lang/String;I)Z
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index af33cbc..38b9647 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -285,14 +285,21 @@
     @VisibleForTesting
     final class Constants extends ContentObserver {
         // Key names stored in the settings value.
-        private static final String KEY_MIN_FUTURITY = "min_futurity";
-        private static final String KEY_MIN_INTERVAL = "min_interval";
-        private static final String KEY_MAX_INTERVAL = "max_interval";
-        private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";
-        private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
-        private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
+        @VisibleForTesting
+        static final String KEY_MIN_FUTURITY = "min_futurity";
+        @VisibleForTesting
+        static final String KEY_MIN_INTERVAL = "min_interval";
+        @VisibleForTesting
+        static final String KEY_MAX_INTERVAL = "max_interval";
+        @VisibleForTesting
+        static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";
+        @VisibleForTesting
+        static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
+        @VisibleForTesting
+        static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
                 = "allow_while_idle_whitelist_duration";
-        private static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
+        @VisibleForTesting
+        static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
 
         // Keys for specifying throttling delay based on app standby bucketing
         private final String[] KEYS_APP_STANDBY_DELAY = {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 0b30ff5c..af9d4c8 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -54,6 +54,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -116,6 +117,11 @@
 
        STATE_ACTIVE [label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"]
        STATE_INACTIVE [label="STATE_INACTIVE\nScreen off AND Not charging"]
+       STATE_QUICK_DOZE_DELAY [
+         label="STATE_QUICK_DOZE_DELAY\n"
+             + "Screen off AND Not charging\n"
+             + "Location, motion detection, and significant motion monitoring turned off"
+       ]
        STATE_IDLE_PENDING [
          label="STATE_IDLE_PENDING\nSignificant motion monitoring turned on"
        ]
@@ -125,26 +131,40 @@
        ]
        STATE_IDLE [
          label="STATE_IDLE\nLocation and motion detection turned off\n"
-             + "Significant motion monitoring still on"
+             + "Significant motion monitoring state unchanged"
        ]
        STATE_IDLE_MAINTENANCE [label="STATE_IDLE_MAINTENANCE\n"]
 
-       STATE_ACTIVE -> STATE_INACTIVE [label="becomeInactiveIfAppropriateLocked()"]
+       STATE_ACTIVE -> STATE_INACTIVE [
+         label="becomeInactiveIfAppropriateLocked() AND Quick Doze not enabled"
+       ]
+       STATE_ACTIVE -> STATE_QUICK_DOZE_DELAY [
+         label="becomeInactiveIfAppropriateLocked() AND Quick Doze enabled"
+       ]
 
        STATE_INACTIVE -> STATE_ACTIVE [
          label="handleMotionDetectedLocked(), becomeActiveLocked()"
        ]
        STATE_INACTIVE -> STATE_IDLE_PENDING [label="stepIdleStateLocked()"]
+       STATE_INACTIVE -> STATE_QUICK_DOZE_DELAY [
+         label="becomeInactiveIfAppropriateLocked() AND Quick Doze enabled"
+       ]
 
        STATE_IDLE_PENDING -> STATE_ACTIVE [
          label="handleMotionDetectedLocked(), becomeActiveLocked()"
        ]
        STATE_IDLE_PENDING -> STATE_SENSING [label="stepIdleStateLocked()"]
+       STATE_IDLE_PENDING -> STATE_QUICK_DOZE_DELAY [
+         label="becomeInactiveIfAppropriateLocked() AND Quick Doze enabled"
+       ]
 
        STATE_SENSING -> STATE_ACTIVE [
          label="handleMotionDetectedLocked(), becomeActiveLocked()"
        ]
        STATE_SENSING -> STATE_LOCATING [label="stepIdleStateLocked()"]
+       STATE_SENSING -> STATE_QUICK_DOZE_DELAY [
+         label="becomeInactiveIfAppropriateLocked() AND Quick Doze enabled"
+       ]
        STATE_SENSING -> STATE_IDLE [
          label="stepIdleStateLocked()\n"
              + "No Location Manager OR (no Network provider AND no GPS provider)"
@@ -153,8 +173,16 @@
        STATE_LOCATING -> STATE_ACTIVE [
          label="handleMotionDetectedLocked(), becomeActiveLocked()"
        ]
+       STATE_LOCATING -> STATE_QUICK_DOZE_DELAY [
+         label="becomeInactiveIfAppropriateLocked() AND Quick Doze enabled"
+       ]
        STATE_LOCATING -> STATE_IDLE [label="stepIdleStateLocked()"]
 
+       STATE_QUICK_DOZE_DELAY -> STATE_ACTIVE [
+         label="handleMotionDetectedLocked(), becomeActiveLocked()"
+       ]
+       STATE_QUICK_DOZE_DELAY -> STATE_IDLE [label="stepIdleStateLocked()"]
+
        STATE_IDLE -> STATE_ACTIVE [label="handleMotionDetectedLocked(), becomeActiveLocked()"]
        STATE_IDLE -> STATE_IDLE_MAINTENANCE [label="stepIdleStateLocked()"]
 
@@ -252,6 +280,7 @@
     private final AppStateTracker mAppStateTracker;
     private boolean mLightEnabled;
     private boolean mDeepEnabled;
+    private boolean mQuickDozeActivated;
     private boolean mForceIdle;
     private boolean mNetworkConnected;
     private boolean mScreenOn;
@@ -287,6 +316,12 @@
     /** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
     @VisibleForTesting
     static final int STATE_IDLE_MAINTENANCE = 6;
+    /**
+     * Device is inactive and should go straight into idle (foregoing motion and location
+     * monitoring), but allow some time for current work to complete first.
+     */
+    @VisibleForTesting
+    static final int STATE_QUICK_DOZE_DELAY = 7;
 
     @VisibleForTesting
     static String stateToString(int state) {
@@ -298,6 +333,7 @@
             case STATE_LOCATING: return "LOCATING";
             case STATE_IDLE: return "IDLE";
             case STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
+            case STATE_QUICK_DOZE_DELAY: return "QUICK_DOZE_DELAY";
             default: return Integer.toString(state);
         }
     }
@@ -688,6 +724,7 @@
         private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
         private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
         private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
+        private static final String KEY_QUICK_DOZE_DELAY_TIMEOUT = "quick_doze_delay_to";
         private static final String KEY_IDLE_TIMEOUT = "idle_to";
         private static final String KEY_MAX_IDLE_TIMEOUT = "max_idle_to";
         private static final String KEY_IDLE_FACTOR = "idle_factor";
@@ -864,6 +901,15 @@
         public float IDLE_PENDING_FACTOR;
 
         /**
+         * This is amount of time we will wait from the point where we go into
+         * STATE_QUICK_DOZE_DELAY until we actually go into STATE_IDLE, while waiting for jobs
+         * and other current activity to finish.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_QUICK_DOZE_DELAY_TIMEOUT
+         */
+        public long QUICK_DOZE_DELAY_TIMEOUT;
+
+        /**
          * This is the initial time that we want to sit in the idle state before waking up
          * again to return to pending idle and allowing normal work to run.
          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
@@ -999,6 +1045,8 @@
                         !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
                 IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,
                         2f);
+                QUICK_DOZE_DELAY_TIMEOUT = mParser.getDurationMillis(
+                        KEY_QUICK_DOZE_DELAY_TIMEOUT, !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L);
                 IDLE_TIMEOUT = mParser.getDurationMillis(KEY_IDLE_TIMEOUT,
                         !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
                 MAX_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_MAX_IDLE_TIMEOUT,
@@ -1093,6 +1141,10 @@
             pw.print("    "); pw.print(KEY_IDLE_PENDING_FACTOR); pw.print("=");
             pw.println(IDLE_PENDING_FACTOR);
 
+            pw.print("    "); pw.print(KEY_QUICK_DOZE_DELAY_TIMEOUT); pw.print("=");
+            TimeUtils.formatDuration(QUICK_DOZE_DELAY_TIMEOUT, pw);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_IDLE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(IDLE_TIMEOUT, pw);
             pw.println();
@@ -1738,6 +1790,16 @@
                         mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
 
+                mLocalPowerManager.registerLowPowerModeObserver(ServiceType.QUICK_DOZE,
+                        state -> {
+                            synchronized (DeviceIdleController.this) {
+                                updateQuickDozeFlagLocked(state.batterySaverEnabled);
+                            }
+                        });
+                updateQuickDozeFlagLocked(
+                        mLocalPowerManager.getLowPowerState(
+                                ServiceType.QUICK_DOZE).batterySaverEnabled);
+
                 mLocalActivityTaskManager.registerScreenObserver(mScreenObserver);
 
                 passWhiteListsToForceAppStandbyTrackerLocked();
@@ -2211,7 +2273,9 @@
 
     @VisibleForTesting
     boolean isScreenOn() {
-        return mScreenOn;
+        synchronized (this) {
+            return mScreenOn;
+        }
     }
 
     void updateInteractivityLocked() {
@@ -2235,7 +2299,9 @@
 
     @VisibleForTesting
     boolean isCharging() {
-        return mCharging;
+        synchronized (this) {
+            return mCharging;
+        }
     }
 
     void updateChargingLocked(boolean charging) {
@@ -2253,6 +2319,27 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isQuickDozeEnabled() {
+        synchronized (this) {
+            return mQuickDozeActivated;
+        }
+    }
+
+    /** Updates the quick doze flag and enters deep doze if appropriate. */
+    @VisibleForTesting
+    void updateQuickDozeFlagLocked(boolean enabled) {
+        if (DEBUG) Slog.i(TAG, "updateQuickDozeFlagLocked: enabled=" + enabled);
+        mQuickDozeActivated = enabled;
+        if (enabled) {
+            // If Quick Doze is enabled, see if we should go straight into it.
+            becomeInactiveIfAppropriateLocked();
+        }
+        // Going from Deep Doze to Light Idle (if quick doze becomes disabled) is tricky and
+        // probably not worth the overhead, so leave in deep doze if that's the case until the
+        // next natural time to come out of it.
+    }
+
     void keyguardShowingLocked(boolean showing) {
         if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing);
         if (mScreenLocked != showing) {
@@ -2304,14 +2391,34 @@
     void becomeInactiveIfAppropriateLocked() {
         if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
         if ((!mScreenOn && !mCharging) || mForceIdle) {
-            // Screen has turned off; we are now going to become inactive and start
-            // waiting to see if we will ultimately go idle.
-            if (mState == STATE_ACTIVE && mDeepEnabled) {
-                mState = STATE_INACTIVE;
-                if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
-                resetIdleManagementLocked();
-                scheduleAlarmLocked(mInactiveTimeout, false);
-                EventLogTags.writeDeviceIdle(mState, "no activity");
+            // Become inactive and determine if we will ultimately go idle.
+            if (mDeepEnabled) {
+                if (mQuickDozeActivated) {
+                    if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
+                            || mState == STATE_IDLE_MAINTENANCE) {
+                        // Already "idling". Don't want to restart the process.
+                        // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
+                        // values, so returning here is safe.
+                        return;
+                    }
+                    if (DEBUG) {
+                        Slog.d(TAG, "Moved from "
+                                + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
+                    }
+                    mState = STATE_QUICK_DOZE_DELAY;
+                    // Make sure any motion sensing or locating is stopped.
+                    resetIdleManagementLocked();
+                    // Wait a small amount of time in case something (eg: background service from
+                    // recently closed app) needs to finish running.
+                    scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+                    EventLogTags.writeDeviceIdle(mState, "no activity");
+                } else if (mState == STATE_ACTIVE) {
+                    mState = STATE_INACTIVE;
+                    if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
+                    resetIdleManagementLocked();
+                    scheduleAlarmLocked(mInactiveTimeout, false);
+                    EventLogTags.writeDeviceIdle(mState, "no activity");
+                }
             }
             if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
                 mLightState = LIGHT_STATE_INACTIVE;
@@ -2473,9 +2580,6 @@
                 // for motion and sleep some more while doing so.
                 startMonitoringMotionLocked();
                 scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
-                // Reset the upcoming idle delays.
-                mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
-                mNextIdleDelay = mConstants.IDLE_TIMEOUT;
                 mState = STATE_IDLE_PENDING;
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
                 EventLogTags.writeDeviceIdle(mState, reason);
@@ -2528,6 +2632,13 @@
                 cancelLocatingLocked();
                 mAnyMotionDetector.stop();
 
+                // Intentional fallthrough -- time to go into IDLE state.
+            case STATE_QUICK_DOZE_DELAY:
+                // Reset the upcoming idle delays.
+                mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
+                mNextIdleDelay = mConstants.IDLE_TIMEOUT;
+
+                // Everything is in place to go into IDLE state.
             case STATE_IDLE_MAINTENANCE:
                 scheduleAlarmLocked(mNextIdleDelay, true);
                 if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
@@ -2782,11 +2893,15 @@
 
     void scheduleAlarmLocked(long delay, boolean idleUntil) {
         if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
-        if (mMotionSensor == null) {
+        if (mMotionSensor == null && !(mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
+                  || mState == STATE_IDLE_MAINTENANCE)) {
             // If there is no motion sensor on this device, then we won't schedule
             // alarms, because we can't determine if the device is not moving.  This effectively
             // turns off normal execution of device idling, although it is still possible to
             // manually poke it by pretending like the alarm is going off.
+            // STATE_QUICK_DOZE_DELAY skips the motion sensing so if the state is past the motion
+            // sensing stage (ie, is QUICK_DOZE_DELAY, IDLE, or IDLE_MAINTENANCE), then idling
+            // can continue until the user interacts with the device.
             return;
         }
         mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
@@ -3215,6 +3330,7 @@
                             case "light": pw.println(lightStateToString(mLightState)); break;
                             case "deep": pw.println(stateToString(mState)); break;
                             case "force": pw.println(mForceIdle); break;
+                            case "quick": pw.println(mQuickDozeActivated); break;
                             case "screen": pw.println(mScreenOn); break;
                             case "charging": pw.println(mCharging); break;
                             case "network": pw.println(mNetworkConnected); break;
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 6677541..2dee3a0 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -27,6 +27,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.format.DateFormat;
 import android.util.KeyValueListParser;
 import android.util.Slog;
 
@@ -91,7 +92,9 @@
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-        List<LooperStats.ExportedEntry> entries = mStats.getEntries();
+        pw.print("Start time: ");
+        pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStats.getStartTimeMillis()));
+        final List<LooperStats.ExportedEntry> entries = mStats.getEntries();
         entries.sort(Comparator
                 .comparing((LooperStats.ExportedEntry entry) -> entry.workSourceUid)
                 .thenComparing(entry -> entry.threadName)
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4070bca..405a2d0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1138,7 +1138,7 @@
             for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) {
                 ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j);
                 if (active.mUid == uidRec.uid) {
-                    if (uidRec.curProcState <= ActivityManager.PROCESS_STATE_TOP) {
+                    if (uidRec.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP) {
                         if (!active.mAppOnTop) {
                             active.mAppOnTop = true;
                             changed = true;
@@ -1257,7 +1257,7 @@
                                 active.mShownWhileScreenOn = mScreenOn;
                                 if (r.app != null) {
                                     active.mAppOnTop = active.mShownWhileTop =
-                                            r.app.uidRecord.curProcState
+                                            r.app.uidRecord.getCurProcState()
                                                     <= ActivityManager.PROCESS_STATE_TOP;
                                 }
                                 active.mStartTime = active.mStartVisibleTime
diff --git a/services/core/java/com/android/server/am/ActiveUids.java b/services/core/java/com/android/server/am/ActiveUids.java
new file mode 100644
index 0000000..4e1435e
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActiveUids.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import android.util.SparseArray;
+
+/** Class for tracking active uids for running processes. */
+final class ActiveUids {
+
+    private ActivityManagerService mService;
+
+    private boolean mPostChangesToAtm;
+    private final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
+
+    ActiveUids(ActivityManagerService service, boolean postChangesToAtm) {
+        mService = service;
+        mPostChangesToAtm = postChangesToAtm;
+    }
+
+    void put(int uid, UidRecord value) {
+        mActiveUids.put(uid, value);
+        if (mPostChangesToAtm) {
+            mService.mAtmInternal.onUidActive(uid, value.getCurProcState());
+        }
+    }
+
+    void remove(int uid) {
+        mActiveUids.remove(uid);
+        if (mPostChangesToAtm) {
+            mService.mAtmInternal.onUidInactive(uid);
+        }
+    }
+
+    void clear() {
+        mActiveUids.clear();
+        if (mPostChangesToAtm) {
+            mService.mAtmInternal.onActiveUidsCleared();
+        }
+    }
+
+    UidRecord get(int uid) {
+        return mActiveUids.get(uid);
+    }
+
+    int size() {
+        return mActiveUids.size();
+    }
+
+    UidRecord valueAt(int index) {
+        return mActiveUids.valueAt(index);
+    }
+
+    int keyAt(int index) {
+        return mActiveUids.keyAt(index);
+    }
+
+    int indexOfKey(int uid) {
+        return mActiveUids.indexOfKey(uid);
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4eb964a..1b74ed0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,6 +26,7 @@
 import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.AppOpsManager.OP_NONE;
@@ -743,16 +744,14 @@
      */
     boolean mFullPssPending = false;
 
-    /**
-     * Track all uids that have actively running processes.
-     */
-    final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
+    /** Track all uids that have actively running processes. */
+    final ActiveUids mActiveUids;
 
     /**
      * This is for verifying the UID report flow.
      */
     static final boolean VALIDATE_UID_STATES = true;
-    final SparseArray<UidRecord> mValidateUids = new SparseArray<>();
+    final ActiveUids mValidateUids = new ActiveUids(this, false /* postChangesToAtm */);
 
     /**
      * Fingerprints (hashCode()) of stack traces that we've
@@ -979,7 +978,7 @@
         }
     }
 
-    final SparseArray<PendingTempWhitelist> mPendingTempWhitelist = new SparseArray<>();
+    final PendingTempWhitelists mPendingTempWhitelist = new PendingTempWhitelists(this);
 
     /**
      * Information about and control over application operations
@@ -2118,6 +2117,7 @@
         mContext = mInjector.getContext();
         mUiContext = null;
         mAppErrors = null;
+        mActiveUids = new ActiveUids(this, false /* postChangesToAtm */);
         mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
         mBatteryStatsService = null;
         mHandler = hasHandlerThread ? new MainHandler(handlerThread.getLooper()) : null;
@@ -2180,6 +2180,7 @@
         mServices = new ActiveServices(this);
         mProviderMap = new ProviderMap(this);
         mAppErrors = new AppErrors(mUiContext, this);
+        mActiveUids = new ActiveUids(this, true /* postChangesToAtm */);
 
         final File systemDir = SystemServiceManager.ensureSystemDir();
 
@@ -2701,7 +2702,7 @@
                     "getPackageProcessState");
         }
 
-        int procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+        int procState = PROCESS_STATE_NONEXISTENT;
         synchronized (this) {
             for (int i=mProcessList.mLruProcesses.size()-1; i>=0; i--) {
                 final ProcessRecord proc = mProcessList.mLruProcesses.get(i);
@@ -2837,7 +2838,7 @@
                 } else {
                     UidRecord validateUid = mValidateUids.get(item.uid);
                     if (validateUid == null) {
-                        validateUid = new UidRecord(item.uid);
+                        validateUid = new UidRecord(item.uid, mAtmInternal);
                         mValidateUids.put(item.uid, validateUid);
                     }
                     if ((item.change & UidRecord.CHANGE_IDLE) != 0) {
@@ -2845,7 +2846,7 @@
                     } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
                         validateUid.idle = false;
                     }
-                    validateUid.curProcState = validateUid.setProcState = item.processState;
+                    validateUid.setCurProcState(validateUid.setProcState = item.processState);
                     validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
                 }
             }
@@ -2921,8 +2922,7 @@
                                 final boolean newAboveCut = item.processState <= reg.cutpoint;
                                 doReport = lastAboveCut != newAboveCut;
                             } else {
-                                doReport = item.processState
-                                        != ActivityManager.PROCESS_STATE_NONEXISTENT;
+                                doReport = item.processState != PROCESS_STATE_NONEXISTENT;
                             }
                         }
                         if (doReport) {
@@ -5140,7 +5140,7 @@
             if (uidRec == null || uidRec.idle) {
                 return false;
             }
-            return uidRec.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            return uidRec.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
         }
     }
 
@@ -5154,7 +5154,7 @@
 
     int getUidStateLocked(int uid) {
         UidRecord uidRec = mActiveUids.get(uid);
-        return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+        return uidRec == null ? PROCESS_STATE_NONEXISTENT : uidRec.getCurProcState();
     }
 
     // =========================================================
@@ -5208,8 +5208,7 @@
         synchronized (mPidsSelfLocked) {
             for (int i = 0; i < pids.length; i++) {
                 ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
-                states[i] = (pr == null) ? ActivityManager.PROCESS_STATE_NONEXISTENT :
-                        pr.getCurProcState();
+                states[i] = (pr == null) ? PROCESS_STATE_NONEXISTENT : pr.getCurProcState();
                 if (scores != null) {
                     scores[i] = (pr == null) ? ProcessList.INVALID_ADJ : pr.curAdj;
                 }
@@ -7617,7 +7616,7 @@
 
         synchronized (this) {
             UidRecord uidRec = mActiveUids.get(uid);
-            return uidRec != null ? uidRec.curProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+            return uidRec != null ? uidRec.getCurProcState() : PROCESS_STATE_NONEXISTENT;
         }
     }
 
@@ -9566,7 +9565,7 @@
         return -1;
     }
 
-    boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, SparseArray<UidRecord> uids,
+    boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, ActiveUids uids,
                 String header, boolean needSep) {
         boolean printed = false;
         for (int i=0; i<uids.size(); i++) {
@@ -16227,8 +16226,7 @@
         mPendingPssProcesses.clear();
         for (int i = mProcessList.getLruSizeLocked() - 1; i >= 0; i--) {
             ProcessRecord app = mProcessList.mLruProcesses.get(i);
-            if (app.thread == null
-                    || app.getCurProcState() == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+            if (app.thread == null || app.getCurProcState() == PROCESS_STATE_NONEXISTENT) {
                 continue;
             }
             if (memLowered || (always && now >
@@ -16609,7 +16607,7 @@
                 }
             }
         }
-        if (app.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT
+        if (app.setProcState == PROCESS_STATE_NONEXISTENT
                 || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
             if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
                 // Experimental code to more aggressively collect pss while
@@ -16798,8 +16796,7 @@
             }
         }
         pendingChange.change = change;
-        pendingChange.processState = uidRec != null
-                ? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+        pendingChange.processState = uidRec != null ? uidRec.setProcState : PROCESS_STATE_NONEXISTENT;
         pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid);
         pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
         if (uidRec != null) {
@@ -17234,8 +17231,8 @@
                     final UidRecord uidRec = app.uidRecord;
                     if (uidRec != null) {
                         uidRec.ephemeral = app.info.isInstantApp();
-                        if (uidRec.curProcState > app.getCurProcState()) {
-                            uidRec.curProcState = app.getCurProcState();
+                        if (uidRec.getCurProcState() > app.getCurProcState()) {
+                            uidRec.setCurProcState(app.getCurProcState());
                         }
                         if (app.hasForegroundServices()) {
                             uidRec.foregroundServices = true;
@@ -17442,14 +17439,14 @@
         for (int i=mActiveUids.size()-1; i>=0; i--) {
             final UidRecord uidRec = mActiveUids.valueAt(i);
             int uidChange = UidRecord.CHANGE_PROCSTATE;
-            if (uidRec.curProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
-                    && (uidRec.setProcState != uidRec.curProcState
+            if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
+                    && (uidRec.setProcState != uidRec.getCurProcState()
                            || uidRec.setWhitelist != uidRec.curWhitelist)) {
-                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
-                        "Changes in " + uidRec + ": proc state from " + uidRec.setProcState
-                        + " to " + uidRec.curProcState + ", whitelist from " + uidRec.setWhitelist
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
+                        + ": proc state from " + uidRec.setProcState + " to "
+                        + uidRec.getCurProcState() + ", whitelist from " + uidRec.setWhitelist
                         + " to " + uidRec.curWhitelist);
-                if (ActivityManager.isProcStateBackground(uidRec.curProcState)
+                if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
                         && !uidRec.curWhitelist) {
                     // UID is now in the background (and not on the temp whitelist).  Was it
                     // previously in the foreground (or on the temp whitelist)?
@@ -17482,17 +17479,16 @@
                 }
                 final boolean wasCached = uidRec.setProcState
                         > ActivityManager.PROCESS_STATE_RECEIVER;
-                final boolean isCached = uidRec.curProcState
+                final boolean isCached = uidRec.getCurProcState()
                         > ActivityManager.PROCESS_STATE_RECEIVER;
-                if (wasCached != isCached ||
-                        uidRec.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+                if (wasCached != isCached || uidRec.setProcState == PROCESS_STATE_NONEXISTENT) {
                     uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
                 }
-                uidRec.setProcState = uidRec.curProcState;
+                uidRec.setProcState = uidRec.getCurProcState();
                 uidRec.setWhitelist = uidRec.curWhitelist;
                 uidRec.setIdle = uidRec.idle;
                 enqueueUidChangeLocked(uidRec, -1, uidChange);
-                noteUidProcessState(uidRec.uid, uidRec.curProcState);
+                noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
                 if (uidRec.foregroundServices) {
                     mServices.foregroundServiceProcStateChangedLocked(uidRec);
                 }
@@ -17653,7 +17649,7 @@
                 continue;
             }
             // If process state is not changed, then there's nothing to do.
-            if (uidRec.setProcState == uidRec.curProcState) {
+            if (uidRec.setProcState == uidRec.getCurProcState()) {
                 continue;
             }
             final int blockState = getBlockStateForUid(uidRec);
@@ -17717,8 +17713,9 @@
     @VisibleForTesting
     int getBlockStateForUid(UidRecord uidRec) {
         // Denotes whether uid's process state is currently allowed network access.
-        final boolean isAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.curProcState)
-                || isProcStateAllowedWhileOnRestrictBackground(uidRec.curProcState);
+        final boolean isAllowed =
+                isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getCurProcState())
+                || isProcStateAllowedWhileOnRestrictBackground(uidRec.getCurProcState());
         // Denotes whether uid's process state was previously allowed network access.
         final boolean wasAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.setProcState)
                 || isProcStateAllowedWhileOnRestrictBackground(uidRec.setProcState);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 45a0652..fa227a2 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -883,23 +883,23 @@
 
         try {
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "logActivityStart");
-            final int callingUidProcState = mService.mAm.getUidStateLocked(callingUid);
+            final int callingUidProcState = mService.getUidStateLocked(callingUid);
             final boolean callingUidHasAnyVisibleWindow =
                     mService.mWindowManager.isAnyWindowVisibleForUid(callingUid);
             final int realCallingUidProcState = (callingUid == realCallingUid)
                     ? callingUidProcState
-                    : mService.mAm.getUidStateLocked(realCallingUid);
+                    : mService.getUidStateLocked(realCallingUid);
             final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
                     ? callingUidHasAnyVisibleWindow
                     : mService.mWindowManager.isAnyWindowVisibleForUid(realCallingUid);
             final String targetPackage = r.packageName;
             final int targetUid = (r.appInfo != null) ? r.appInfo.uid : -1;
-            final int targetUidProcState = mService.mAm.getUidStateLocked(targetUid);
+            final int targetUidProcState = mService.getUidStateLocked(targetUid);
             final boolean targetUidHasAnyVisibleWindow = (targetUid != -1)
                     ? mService.mWindowManager.isAnyWindowVisibleForUid(targetUid)
                     : false;
             final String targetWhitelistTag = (targetUid != -1)
-                    ? mService.mAm.getPendingTempWhitelistTagForUidLocked(targetUid)
+                    ? mService.getPendingTempWhitelistTagForUidLocked(targetUid)
                     : null;
 
             mSupervisor.getActivityMetricsLogger().logActivityStart(intent, callerApp, r,
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index f79d9aa..02707fb 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -19,7 +19,6 @@
 import static android.Manifest.permission.BIND_VOICE_INTERACTION;
 import static android.Manifest.permission.CHANGE_CONFIGURATION;
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
-import static android.Manifest.permission.FILTER_EVENTS;
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
@@ -27,10 +26,11 @@
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.Manifest.permission.STOP_APP_SWITCHES;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.AppOpsManager.OP_NONE;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -71,6 +71,10 @@
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
 
+import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
+import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
+import static com.android.server.am.ActivityManagerService.dumpStackTraces;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONTROLLER;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER;
@@ -81,12 +85,21 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
+        .PREVIOUS_PROC_VISIBLE_TIME_MS;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
+        .MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
+        .PACKAGE;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
+import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
+import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE;
@@ -104,19 +117,8 @@
 import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.MY_PID;
-import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
-import static com.android.server.am.ActivityManagerService.dumpStackTraces;
-import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
-import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
-import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
-import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.am.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
 import static com.android.server.am.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
@@ -330,7 +332,6 @@
     final ActivityThread mSystemThread;
     H mH;
     UiHandler mUiHandler;
-    ActivityManagerService mAm;
     ActivityManagerInternal mAmInternal;
     UriGrantsManagerInternal mUgmInternal;
     private PackageManagerInternal mPmInternal;
@@ -347,6 +348,9 @@
     WindowManagerService mWindowManager;
     private UserManagerService mUserManager;
     private AppOpsService mAppOpsService;
+    /** All active uids in the system. */
+    private final SparseArray<Integer> mActiveUids = new SparseArray<>();
+    private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
     /** All processes currently running that might have a window organized by name. */
     final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
     /** All processes we currently have running mapped by pid */
@@ -705,10 +709,9 @@
     }
 
     // TODO: Will be converted to WM lock once transition is complete.
-    void setActivityManagerService(ActivityManagerService am, Looper looper,
+    void setActivityManagerService(Object globalLock, Looper looper,
             IntentFirewall intentFirewall, PendingIntentController intentController) {
-        mAm = am;
-        mGlobalLock = mAm;
+        mGlobalLock = globalLock;
         mH = new H(looper);
         mUiHandler = new UiHandler();
         mIntentFirewall = intentFirewall;
@@ -4761,7 +4764,8 @@
         }
 
         for (int i = mPidMap.size() - 1; i >= 0; i--) {
-            WindowProcessController app = mPidMap.get(mPidMap.keyAt(i));
+            final int pid = mPidMap.keyAt(i);
+            final WindowProcessController app = mPidMap.get(pid);
             if (DEBUG_CONFIGURATION) {
                 Slog.v(TAG_CONFIGURATION, "Update process config of "
                         + app.mName + " to new config " + configCopy);
@@ -5455,6 +5459,18 @@
         return null;
     }
 
+    int getUidStateLocked(int uid) {
+        return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
+    }
+
+    /**
+     * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
+     * the whitelist
+     */
+    String getPendingTempWhitelistTagForUidLocked(int uid) {
+        return mPendingTempWhitelist.get(uid);
+    }
+
     void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
         if (true || Build.IS_USER) {
             return;
@@ -6015,7 +6031,7 @@
          * @param displayId The ID of the display showing the IME.
          */
         @Override
-        public void onImeWindowSetOnDisplay(int pid, int displayId) {
+        public void onImeWindowSetOnDisplay(final int pid, final int displayId) {
             if (pid == MY_PID || pid < 0) {
                 if (DEBUG_CONFIGURATION) {
                     Slog.w(TAG,
@@ -6025,29 +6041,28 @@
             }
             mH.post(() -> {
                 synchronized (mGlobalLock) {
-                    // Check if display is initialized in AM.
-                    if (!mStackSupervisor.isDisplayAdded(displayId)) {
-                        // Call come when display is not yet added or has already been removed.
+                    final ActivityDisplay activityDisplay =
+                            mStackSupervisor.getActivityDisplay(displayId);
+                    if (activityDisplay == null) {
+                        // Call might come when display is not yet added or has been removed.
                         if (DEBUG_CONFIGURATION) {
                             Slog.w(TAG, "Trying to update display configuration for non-existing "
-                                            + "displayId=" + displayId);
+                                    + "displayId=" + displayId);
                         }
                         return;
                     }
-                    final WindowProcessController imeProcess = mPidMap.get(pid);
-                    if (imeProcess == null) {
+                    final WindowProcessController process = mPidMap.get(pid);
+                    if (process == null) {
                         if (DEBUG_CONFIGURATION) {
-                            Slog.w(TAG, "Trying to update display configuration for invalid pid: "
-                                            + pid);
+                            Slog.w(TAG, "Trying to update display configuration for invalid "
+                                    + "process, pid=" + pid);
                         }
                         return;
                     }
-                    // Fetch the current override configuration of the display and set it to the
-                    // process global configuration.
-                    imeProcess.onConfigurationChanged(
-                            mStackSupervisor.getDisplayOverrideConfiguration(displayId));
+                    process.registerDisplayConfigurationListenerLocked(activityDisplay);
                 }
             });
+
         }
 
         @Override
@@ -6630,5 +6645,49 @@
                 return mStackSupervisor.finishTopCrashedActivitiesLocked(crashedApp, reason);
             }
         }
+
+        @Override
+        public void onUidActive(int uid, int procState) {
+            synchronized (mGlobalLock) {
+                mActiveUids.put(uid, procState);
+            }
+        }
+
+        @Override
+        public void onUidInactive(int uid) {
+            synchronized (mGlobalLock) {
+                mActiveUids.remove(uid);
+            }
+        }
+
+        @Override
+        public void onActiveUidsCleared() {
+            synchronized (mGlobalLock) {
+                mActiveUids.clear();
+            }
+        }
+
+        @Override
+        public void onUidProcStateChanged(int uid, int procState) {
+            synchronized (mGlobalLock) {
+                if (mActiveUids.get(uid) != null) {
+                    mActiveUids.put(uid, procState);
+                }
+            }
+        }
+
+        @Override
+        public void onUidAddedToPendingTempWhitelist(int uid, String tag) {
+            synchronized (mGlobalLock) {
+                mPendingTempWhitelist.put(uid, tag);
+            }
+        }
+
+        @Override
+        public void onUidRemovedFromPendingTempWhitelist(int uid) {
+            synchronized (mGlobalLock) {
+                mPendingTempWhitelist.remove(uid);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/PendingTempWhitelists.java b/services/core/java/com/android/server/am/PendingTempWhitelists.java
new file mode 100644
index 0000000..b36e3c7
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingTempWhitelists.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import android.util.SparseArray;
+
+/** Whitelists of uids to temporarily bypass Power Save mode. */
+final class PendingTempWhitelists {
+
+    private ActivityManagerService mService;
+
+    private final SparseArray<ActivityManagerService.PendingTempWhitelist> mPendingTempWhitelist =
+            new SparseArray<>();
+
+    PendingTempWhitelists(ActivityManagerService service) {
+        mService = service;
+    }
+
+    void put(int uid, ActivityManagerService.PendingTempWhitelist value) {
+        mPendingTempWhitelist.put(uid, value);
+        mService.mAtmInternal.onUidAddedToPendingTempWhitelist(uid, value.tag);
+    }
+
+    void removeAt(int index) {
+        final int uid = mPendingTempWhitelist.keyAt(index);
+        mPendingTempWhitelist.removeAt(index);
+        mService.mAtmInternal.onUidRemovedFromPendingTempWhitelist(uid);
+    }
+
+    ActivityManagerService.PendingTempWhitelist get(int uid) {
+        return mPendingTempWhitelist.get(uid);
+    }
+
+    int size() {
+        return mPendingTempWhitelist.size();
+    }
+
+    ActivityManagerService.PendingTempWhitelist valueAt(int index) {
+        return mPendingTempWhitelist.valueAt(index);
+    }
+
+    int indexOfKey(int key) {
+        return mPendingTempWhitelist.indexOfKey(key);
+    }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index cb6061a..805b979b 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1915,7 +1915,7 @@
         }
         UidRecord uidRec = mService.mActiveUids.get(proc.uid);
         if (uidRec == null) {
-            uidRec = new UidRecord(proc.uid);
+            uidRec = new UidRecord(proc.uid, mService.mAtmInternal);
             // This is the first appearance of the uid, report it now!
             if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                     "Creating new process uid: " + uidRec);
@@ -1927,7 +1927,7 @@
             uidRec.updateHasInternetPermission();
             mService.mActiveUids.put(proc.uid, uidRec);
             EventLogTags.writeAmUidRunning(uidRec.uid);
-            mService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+            mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
         }
         proc.uidRecord = uidRec;
 
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 3b859ed..6cb1097 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -18,7 +18,6 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
-import android.app.ActivityManagerProto;
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -27,14 +26,14 @@
 import android.util.proto.ProtoUtils;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 /**
  * Overall information about a uid that has actively running processes.
  */
 public final class UidRecord {
     final int uid;
-    int curProcState;
+    private int mCurProcState;
     int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
     long lastBackgroundTime;
     boolean ephemeral;
@@ -44,11 +43,12 @@
     boolean idle;
     boolean setIdle;
     int numProcs;
+    final ActivityTaskManagerInternal mAtmInternal;
 
     /**
-     * Sequence number associated with the {@link #curProcState}. This is incremented using
+     * Sequence number associated with the {@link #mCurProcState}. This is incremented using
      * {@link ActivityManagerService#mProcStateSeqCounter}
-     * when {@link #curProcState} changes from background to foreground or vice versa.
+     * when {@link #mCurProcState} changes from background to foreground or vice versa.
      */
     @GuardedBy("networkStateUpdate")
     long curProcStateSeq;
@@ -117,14 +117,26 @@
     ChangeItem pendingChange;
     int lastReportedChange;
 
-    public UidRecord(int _uid) {
+    public UidRecord(int _uid, ActivityTaskManagerInternal atmInternal) {
         uid = _uid;
         idle = true;
+        mAtmInternal = atmInternal;
         reset();
     }
 
+    public int getCurProcState() {
+        return mCurProcState;
+    }
+
+    public void setCurProcState(int curProcState) {
+        mCurProcState = curProcState;
+        if (mAtmInternal != null) {
+            mAtmInternal.onUidProcStateChanged(uid, curProcState);
+        }
+    }
+
     public void reset() {
-        curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+        setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         foregroundServices = false;
     }
 
@@ -148,7 +160,7 @@
     void writeToProto(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(UidRecordProto.UID, uid);
-        proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(curProcState));
+        proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(mCurProcState));
         proto.write(UidRecordProto.EPHEMERAL, ephemeral);
         proto.write(UidRecordProto.FG_SERVICES, foregroundServices);
         proto.write(UidRecordProto.WHILELIST, curWhitelist);
@@ -178,7 +190,7 @@
         sb.append(' ');
         UserHandle.formatUid(sb, uid);
         sb.append(' ');
-        sb.append(ProcessList.makeProcStateString(curProcState));
+        sb.append(ProcessList.makeProcStateString(mCurProcState));
         if (ephemeral) {
             sb.append(" ephemeral");
         }
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index 1743dde..94f1002 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -17,20 +17,22 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.view.Display.INVALID_DISPLAY;
 
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
 import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
 import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityTaskManagerService
+        .INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
@@ -47,11 +49,12 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
-
 import android.util.proto.ProtoOutputStream;
+
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.wm.ConfigurationContainer;
+import com.android.server.wm.ConfigurationContainerListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -67,7 +70,8 @@
  * window manager so the window manager lock is held and appropriate permissions are checked before
  * calls are allowed to proceed.
  */
-public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer> {
+public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer>
+        implements ConfigurationContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_ATM;
     private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
@@ -147,6 +151,8 @@
 
     // Last configuration that was reported to the process.
     private final Configuration mLastReportedConfiguration;
+    // Registered display id as a listener to override config change
+    private int mDisplayId;
 
     WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name,
             int uid, int userId, Object owner, WindowProcessListener listener,
@@ -159,6 +165,7 @@
         mListener = listener;
         mAtm = atm;
         mLastReportedConfiguration = new Configuration();
+        mDisplayId = INVALID_DISPLAY;
         if (config != null) {
             onConfigurationChanged(config);
         }
@@ -704,6 +711,30 @@
         mListener.appDied();
     }
 
+    void registerDisplayConfigurationListenerLocked(ActivityDisplay activityDisplay) {
+        if (activityDisplay == null) {
+            return;
+        }
+        // A process can only register to one display to listener to the override configuration
+        // change. Unregister existing listener if it has one before register the new one.
+        unregisterDisplayConfigurationListenerLocked();
+        mDisplayId = activityDisplay.mDisplayId;
+        activityDisplay.registerConfigurationChangeListener(this);
+    }
+
+    private void unregisterDisplayConfigurationListenerLocked() {
+        if (mDisplayId == INVALID_DISPLAY) {
+            return;
+        }
+        final ActivityDisplay activityDisplay =
+                mAtm.mStackSupervisor.getActivityDisplay(mDisplayId);
+        if (activityDisplay != null) {
+            mAtm.mStackSupervisor.getActivityDisplay(
+                    mDisplayId).unregisterConfigurationChangeListener(this);
+        }
+        mDisplayId = INVALID_DISPLAY;
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newGlobalConfig) {
         super.onConfigurationChanged(newGlobalConfig);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 5698fdf..5ed6263 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1615,6 +1615,15 @@
     }
 
     @Override
+    public void onDbCorruption(String tag, String message, String stacktrace) {
+        Slog.e(tag, message);
+        Slog.e(tag, "at " + stacktrace);
+
+        // TODO: Figure out a better way to report it. b/117886381
+        Slog.wtf(tag, message);
+    }
+
+    @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
             ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 8c35e27..5cbe5b9 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -20,12 +20,17 @@
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.SystemProperties;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IntPair;
+import com.android.server.IoThread;
 
 import libcore.io.IoUtils;
 
@@ -65,10 +70,11 @@
      */
     public static synchronized SyncLogger getInstance() {
         if (sInstance == null) {
+            final String flag = SystemProperties.get("debug.synclog");
             final boolean enable =
-                    Build.IS_DEBUGGABLE
-                    || "1".equals(SystemProperties.get("debug.synclog"))
-                    || Log.isLoggable(TAG, Log.VERBOSE);
+                    (Build.IS_DEBUGGABLE
+                    || "1".equals(flag)
+                    || Log.isLoggable(TAG, Log.VERBOSE)) && !"0".equals(flag);
             if (enable) {
                 sInstance = new RotatingFileLogger();
             } else {
@@ -142,8 +148,11 @@
 
         private static final boolean DO_LOGCAT = Log.isLoggable(TAG, Log.DEBUG);
 
+        private final MyHandler mHandler;
+
         RotatingFileLogger() {
             mLogPath = new File(Environment.getDataSystemDirectory(), "syncmanager-log");
+            mHandler = new MyHandler(IoThread.get().getLooper());
         }
 
         @Override
@@ -163,8 +172,12 @@
             if (message == null) {
                 return;
             }
+            final long now = System.currentTimeMillis();
+            mHandler.log(now, message);
+        }
+
+        void logInner(long now, Object[] message) {
             synchronized (mLock) {
-                final long now = System.currentTimeMillis();
                 openLogLocked(now);
                 if (mLogWriter == null) {
                     return; // Couldn't open log file?
@@ -272,5 +285,28 @@
             } catch (IOException e) {
             }
         }
+
+        private class MyHandler extends Handler {
+            public static final int MSG_LOG_ID = 1;
+
+            MyHandler(Looper looper) {
+                super(looper);
+            }
+
+            public void log(long now, Object[] message) {
+                obtainMessage(MSG_LOG_ID, IntPair.first(now), IntPair.second(now), message)
+                        .sendToTarget();
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_LOG_ID: {
+                        logInner(IntPair.of(msg.arg1, msg.arg2), (Object[]) msg.obj);
+                        break;
+                    }
+                }
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d57214e..e37153e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,6 +15,7 @@
 
 package com.android.server.inputmethod;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -65,6 +66,7 @@
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManagerInternal;
 import android.inputmethodservice.InputMethodService;
 import android.net.Uri;
 import android.os.Binder;
@@ -102,6 +104,8 @@
 import android.util.Slog;
 import android.util.Xml;
 import android.view.ContextThemeWrapper;
+import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.IWindowManager;
 import android.view.InputChannel;
 import android.view.LayoutInflater;
@@ -396,6 +400,7 @@
     };
 
     private void restoreNonVrImeFromSettingsNoCheck() {
+        mIsVrImeStarted = false;
         // switch back to non-VR InputMethod from settings.
         synchronized (mMethodMap) {
             final String lastInputId = mSettings.getSelectedInputMethod();
@@ -600,6 +605,11 @@
      */
     int mCurTokenDisplayId = INVALID_DISPLAY;
 
+    final ImeDisplayValidator mImeDisplayValidator;
+
+    /** True if VR IME started by {@link #startVrInputMethodNoCheck}. */
+    boolean mIsVrImeStarted;
+
     /**
      * If non-null, this is the input method service we are currently connected
      * to.
@@ -1000,6 +1010,7 @@
                     // set this is as current inputMethod without updating settings.
                     setInputMethodEnabledLocked(info.getId(), true);
                     setInputMethodLocked(info.getId(), NOT_A_SUBTYPE_ID);
+                    mIsVrImeStarted = true;
                     break;
                 }
             }
@@ -1396,6 +1407,13 @@
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+        final DisplayManagerInternal displayManagerInternal = LocalServices.getService(
+                DisplayManagerInternal.class);
+        mImeDisplayValidator = (displayId) -> {
+            final DisplayInfo displayInfo = displayManagerInternal.getDisplayInfo(displayId);
+            return displayInfo != null
+                    && (displayInfo.flags & Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0;
+        };
         mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
             @Override
             public void executeMessage(Message msg) {
@@ -1918,8 +1936,10 @@
             // Wait, the client no longer has access to the display.
             return InputBindResult.INVALID_DISPLAY_ID;
         }
-        // Now that the display ID is validated, we trust cs.selfReportedDisplayId for this session.
-        final int displayIdToShowIme = cs.selfReportedDisplayId;
+        // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
+        // session & other conditions.
+        final int displayIdToShowIme = computeImeDisplayIdForTarget(
+                cs.selfReportedDisplayId, mIsVrImeStarted, mImeDisplayValidator);
 
         if (mCurClient != cs) {
             // Was the keyguard locked when switching over to the new client?
@@ -2019,6 +2039,35 @@
         return InputBindResult.IME_NOT_CONNECTED;
     }
 
+    @FunctionalInterface
+    interface ImeDisplayValidator {
+        boolean displayCanShowIme(int displayId);
+    }
+
+    /**
+     * Find the display where the IME should be shown.
+     *
+     * @param displayId the ID of the display where the IME client target is.
+     * @param isVrImeStarted {@code true} if VR IME started, {@code false} otherwise.
+     * @param checker instance of {@link ImeDisplayValidator} which is used for
+     *                checking display config to adjust the final target display.
+     * @return The ID of the display where the IME should be shown.
+     */
+    static int computeImeDisplayIdForTarget(int displayId, boolean isVrImeStarted,
+            @NonNull ImeDisplayValidator checker) {
+        // For VR IME, we always show in default display.
+        if (isVrImeStarted) {
+            return DEFAULT_DISPLAY;
+        }
+        if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
+            // We always assume that the default display id suitable to show the IME window.
+            return DEFAULT_DISPLAY;
+        }
+        // Show IME in default display when the display with IME target doesn't support system
+        // decorations.
+        return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
+    }
+
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         synchronized (mMethodMap) {
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 99a04d7..1d0ab8f 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
 import android.hardware.contexthub.V1_0.IContexthub;
@@ -138,6 +139,27 @@
     }
 
     /**
+     * @param intent the intent to register
+     * @param nanoAppId the ID of the nanoapp to send events for
+     * @return true on success, false otherwise
+     */
+    @Override
+    public boolean registerIntent(PendingIntent intent, long nanoAppId) {
+        // TODO: Implement this
+        return false;
+    }
+
+    /**
+     * @param intent the intent to unregister
+     * @return true on success, false otherwise
+     */
+    @Override
+    public boolean unregisterIntent(PendingIntent intent) {
+        // TODO: Implement this
+        return false;
+    }
+
+    /**
      * Closes the connection for this client with the service.
      */
     @Override
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index ed2b79e..4f8e6b6 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -75,6 +75,8 @@
     private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
     private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
     private static final String KEY_AOD_DISABLED = "aod_disabled";
+    // Go into deep Doze as soon as the screen turns off.
+    private static final String KEY_QUICK_DOZE_ENABLED = "quick_doze_enabled";
     private static final String KEY_SEND_TRON_LOG = "send_tron_log";
 
     private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
@@ -228,6 +230,12 @@
     private boolean mAodDisabled;
 
     /**
+     * Whether Quick Doze is enabled or not.
+     */
+    @GuardedBy("mLock")
+    private boolean mQuickDozeEnabled;
+
+    /**
      * Whether BatterySavingStats should send tron events.
      */
     @GuardedBy("mLock")
@@ -392,6 +400,7 @@
         mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
         mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
         mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
+        mQuickDozeEnabled = parser.getBoolean(KEY_QUICK_DOZE_ENABLED, false);
         mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false);
 
         // Get default value from Settings.Secure
@@ -434,6 +443,7 @@
         if (mLaunchBoostDisabled) sb.append("l");
         if (mOptionalSensorsDisabled) sb.append("S");
         if (mAodDisabled) sb.append("o");
+        if (mQuickDozeEnabled) sb.append("q");
         if (mSendTronLog) sb.append("t");
 
         sb.append(mGpsMode);
@@ -502,6 +512,9 @@
                 case ServiceType.AOD:
                     return builder.setBatterySaverEnabled(mAodDisabled)
                             .build();
+                case ServiceType.QUICK_DOZE:
+                    return builder.setBatterySaverEnabled(mQuickDozeEnabled)
+                            .build();
                 default:
                     return builder.setBatterySaverEnabled(realMode)
                             .build();
@@ -562,6 +575,7 @@
             pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
             pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
             pw.println("  " + KEY_AOD_DISABLED + "=" + mAodDisabled);
+            pw.println("  " + KEY_QUICK_DOZE_ENABLED + "=" + mQuickDozeEnabled);
             pw.println("  " + KEY_SEND_TRON_LOG + "=" + mSendTronLog);
             pw.println();
 
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index c162afb..f10fe58 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -88,6 +88,7 @@
 import com.android.internal.os.KernelWakelockStats;
 import com.android.internal.os.LooperStats;
 import com.android.internal.os.PowerProfile;
+import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.StoragedUidIoStatsReader;
 import com.android.internal.util.DumpUtils;
 import com.android.server.BinderCallsStatsService;
@@ -194,6 +195,8 @@
     private static IThermalService sThermalService;
     private File mBaseDir =
             new File(SystemServiceManager.ensureSystemDir(), "stats_companion");
+    @GuardedBy("this")
+    ProcessCpuTracker mProcessCpuTracker = null;
 
     public StatsCompanionService(Context context) {
         super();
@@ -1420,6 +1423,27 @@
         });
     }
 
+    private void pullProcessCpuTime(int tagId, long elapsedNanos, final long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        synchronized (this) {
+            if (mProcessCpuTracker == null) {
+                mProcessCpuTracker = new ProcessCpuTracker(false);
+                mProcessCpuTracker.init();
+            }
+            mProcessCpuTracker.update();
+            for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
+                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                        wallClockNanos);
+                e.writeInt(st.uid);
+                e.writeString(st.name);
+                e.writeLong(st.base_utime);
+                e.writeLong(st.base_stime);
+                pulledData.add(e);
+            }
+        }
+    }
+
     /**
      * Pulls various data.
      */
@@ -1554,6 +1578,10 @@
                 pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.PROCESS_CPU_TIME: {
+                pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 7f9ee84..443d6fe 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -439,4 +439,12 @@
      */
     public abstract int finishTopCrashedActivities(
             WindowProcessController crashedApp, String reason);
+
+    public abstract void onUidActive(int uid, int procState);
+    public abstract void onUidInactive(int uid);
+    public abstract void onActiveUidsCleared();
+    public abstract void onUidProcStateChanged(int uid, int procState);
+
+    public abstract void onUidAddedToPendingTempWhitelist(int uid, String tag);
+    public abstract void onUidRemovedFromPendingTempWhitelist(int uid);
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b7507a4..ef63b9b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -29,13 +29,13 @@
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RenderNode;
 import android.os.Environment;
 import android.os.Handler;
 import android.util.ArraySet;
 import android.util.Slog;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
 import android.view.SurfaceControl;
 import android.view.ThreadedRenderer;
 import android.view.WindowManager.LayoutParams;
@@ -371,7 +371,7 @@
         final RenderNode node = RenderNode.create("TaskSnapshotController", null);
         node.setLeftTopRightBottom(0, 0, width, height);
         node.setClipToBounds(false);
-        final DisplayListCanvas c = node.start(width, height);
+        final RecordingCanvas c = node.start(width, height);
         c.drawColor(color);
         decorPainter.setInsets(mainWindow.getContentInsets(), mainWindow.getStableInsets());
         decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index eacbda1..f16008d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2256,7 +2256,7 @@
     private Configuration getProcessGlobalConfiguration() {
         // For child windows we want to use the pid for the parent window in case the the child
         // window was added from another process.
-        final int pid = isChildWindow() ? getParentWindow().mSession.mPid : mSession.mPid;
+        final int pid = getParentWindow() != null ? getParentWindow().mSession.mPid : mSession.mPid;
         mTempConfiguration.setTo(mService.mProcessConfigurations.get(
                 pid, mService.mRoot.getConfiguration()));
         return mTempConfiguration;
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 7a847f3..ba1d83e 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -2680,9 +2680,7 @@
         return Files.createTempFile(mContext.getCacheDir().toPath(), "backup", ".tmp");
     }
 
-    private static IterableSubject<
-                    ? extends IterableSubject<?, Path, Iterable<Path>>, Path, Iterable<Path>>
-            assertDirectory(Path directory) throws IOException {
+    private static IterableSubject assertDirectory(Path directory) throws IOException {
         return assertThat(oneTimeIterable(Files.newDirectoryStream(directory).iterator()))
                 .named("directory " + directory);
     }
diff --git a/services/tests/mockingservicestests/Android.mk b/services/tests/mockingservicestests/Android.mk
index e6cbb5b..b21b3e4 100644
--- a/services/tests/mockingservicestests/Android.mk
+++ b/services/tests/mockingservicestests/Android.mk
@@ -20,14 +20,11 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    frameworks-base-testutils \
     services.core \
     services.net \
     androidx.test.runner \
     mockito-target-extended-minus-junit4 \
     platform-test-annotations \
-    ShortcutManagerTestUtils \
-    truth-prebuilt \
 
 LOCAL_JAVA_LIBRARIES := android.test.mock android.test.base android.test.runner
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 877c8fa..f85ffc8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -30,10 +30,20 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
+import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
+import static com.android.server.AlarmManagerService.Constants
+        .KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+import static com.android.server.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
+import static com.android.server.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
+import static com.android.server.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
+import static com.android.server.AlarmManagerService.Constants.KEY_MIN_INTERVAL;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 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.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -45,6 +55,7 @@
 import android.app.IUidObserver;
 import android.app.PendingIntent;
 import android.app.usage.UsageStatsManagerInternal;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -52,7 +63,9 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
+import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -68,6 +81,9 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -80,6 +96,8 @@
 
     private AlarmManagerService mService;
     @Mock
+    private ContentResolver mMockResolver;
+    @Mock
     private IActivityManager mIActivityManager;
     @Mock
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
@@ -186,9 +204,11 @@
     public final void setUp() throws Exception {
         mMockingSession = mockitoSession()
                 .initMocks(this)
-                .mockStatic(ActivityManager.class, Answers.CALLS_REAL_METHODS)
+                .spyStatic(ActivityManager.class)
                 .mockStatic(LocalServices.class)
-                .mockStatic(Looper.class, Answers.CALLS_REAL_METHODS)
+                .spyStatic(Looper.class)
+                .spyStatic(Settings.Global.class)
+                .strictness(Strictness.WARN)
                 .startMocking();
         doReturn(mIActivityManager).when(ActivityManager::getService);
         doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class));
@@ -201,15 +221,19 @@
                 .thenReturn(STANDBY_BUCKET_ACTIVE);
         doReturn(Looper.getMainLooper()).when(Looper::myLooper);
 
-        final Context context = InstrumentationRegistry.getTargetContext();
-        mInjector = spy(new Injector(context));
+        final Context context = spy(InstrumentationRegistry.getTargetContext());
+        when(context.getContentResolver()).thenReturn(mMockResolver);
+        doNothing().when(mMockResolver).registerContentObserver(any(), anyBoolean(), any());
+        doReturn("min_futurity=0").when(() ->
+                Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
+        mInjector = new Injector(context);
         mService = new AlarmManagerService(context, mInjector);
         spyOn(mService);
         doNothing().when(mService).publishBinderService(any(), any());
         mService.onStart();
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
-        mService.mConstants.MIN_FUTURITY = 0;
 
+        assertEquals(0, mService.mConstants.MIN_FUTURITY);
         assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
         assertEquals(mService.mClockReceiver, mClockReceiver);
         assertEquals(mService.mWakeLock, mWakeLock);
@@ -235,7 +259,6 @@
         final long triggerTime = mNowElapsedTest + 5000;
         final PendingIntent alarmPi = getNewMockPendingIntent();
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi);
-        verify(mInjector).setAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime);
         assertEquals(triggerTime, mTestTimer.getElapsed());
     }
 
@@ -257,12 +280,45 @@
     }
 
     @Test
+    public void testUpdateConstants() {
+        final StringBuilder constantsBuilder = new StringBuilder();
+        constantsBuilder.append(KEY_MIN_FUTURITY);
+        constantsBuilder.append("=5,");
+        constantsBuilder.append(KEY_MIN_INTERVAL);
+        constantsBuilder.append("=10,");
+        constantsBuilder.append(KEY_MAX_INTERVAL);
+        constantsBuilder.append("=15,");
+        constantsBuilder.append(KEY_ALLOW_WHILE_IDLE_SHORT_TIME);
+        constantsBuilder.append("=20,");
+        constantsBuilder.append(KEY_ALLOW_WHILE_IDLE_LONG_TIME);
+        constantsBuilder.append("=25,");
+        constantsBuilder.append(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+        constantsBuilder.append("=30,");
+        constantsBuilder.append(KEY_LISTENER_TIMEOUT);
+        constantsBuilder.append("=35,");
+
+        doReturn(constantsBuilder.toString()).when(() -> Settings.Global.getString(mMockResolver,
+                Settings.Global.ALARM_MANAGER_CONSTANTS));
+        mService.mConstants.onChange(false, null);
+        assertEquals(5, mService.mConstants.MIN_FUTURITY);
+        assertEquals(10, mService.mConstants.MIN_INTERVAL);
+        assertEquals(15, mService.mConstants.MAX_INTERVAL);
+        assertEquals(20, mService.mConstants.ALLOW_WHILE_IDLE_SHORT_TIME);
+        assertEquals(25, mService.mConstants.ALLOW_WHILE_IDLE_LONG_TIME);
+        assertEquals(30, mService.mConstants.ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+        assertEquals(35, mService.mConstants.LISTENER_TIMEOUT);
+    }
+
+    @Test
     public void testMinFuturity() {
-        mService.mConstants.MIN_FUTURITY = 10;
+        doReturn("min_futurity=10").when(() ->
+                Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
+        mService.mConstants.onChange(false, null);
+        assertEquals(10, mService.mConstants.MIN_FUTURITY);
         final long triggerTime = mNowElapsedTest + 1;
         final long expectedTriggerTime = mNowElapsedTest + mService.mConstants.MIN_FUTURITY;
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, getNewMockPendingIntent());
-        verify(mInjector).setAlarm(ELAPSED_REALTIME_WAKEUP, expectedTriggerTime);
+        assertEquals(expectedTriggerTime, mTestTimer.getElapsed());
     }
 
     @Test
@@ -344,6 +400,31 @@
                 () -> (mTestTimer.getElapsed() == expectedNextTrigger)));
     }
 
+    @Test
+    public void testAlarmRestrictedInBatterSaver() throws PendingIntent.CanceledException {
+        final ArgumentCaptor<AppStateTracker.Listener> listenerArgumentCaptor =
+                ArgumentCaptor.forClass(AppStateTracker.Listener.class);
+        verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture());
+
+        final PendingIntent alarmPi = getNewMockPendingIntent();
+        when(mAppStateTracker.areAlarmsRestricted(TEST_CALLING_UID, TEST_CALLING_PACKAGE,
+                false)).thenReturn(true);
+        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, alarmPi);
+        assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed());
+
+        final SparseArray<ArrayList<AlarmManagerService.Alarm>> restrictedAlarms =
+                mService.mPendingBackgroundAlarms;
+        assertNull(restrictedAlarms.get(TEST_CALLING_UID));
+
+        mNowElapsedTest = mTestTimer.expire();
+        pollingCheck(DEFAULT_TIMEOUT, () -> (restrictedAlarms.get(TEST_CALLING_UID) != null));
+
+        listenerArgumentCaptor.getValue().unblockAlarmsForUid(TEST_CALLING_UID);
+        verify(alarmPi).send(any(Context.class), eq(0), any(Intent.class), any(),
+                any(Handler.class), isNull(), any());
+        assertNull(restrictedAlarms.get(TEST_CALLING_UID));
+    }
+
     @After
     public void tearDown() {
         if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 8afd788..04a8408 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -36,35 +36,36 @@
 import static com.android.server.DeviceIdleController.STATE_IDLE_PENDING;
 import static com.android.server.DeviceIdleController.STATE_INACTIVE;
 import static com.android.server.DeviceIdleController.STATE_LOCATING;
+import static com.android.server.DeviceIdleController.STATE_QUICK_DOZE_DELAY;
 import static com.android.server.DeviceIdleController.STATE_SENSING;
 import static com.android.server.DeviceIdleController.lightStateToString;
 import static com.android.server.DeviceIdleController.stateToString;
 
 import static org.junit.Assert.assertEquals;
-
-import android.net.NetworkInfo;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
-import android.net.ConnectivityManager;
-import android.content.Intent;
 import android.app.IActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.SensorManager;
 import android.location.LocationManager;
 import android.location.LocationProvider;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
 import android.os.SystemClock;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -105,6 +106,8 @@
     private PowerManager mPowerManager;
     @Mock
     private PowerManager.WakeLock mWakeLock;
+    @Mock
+    private PowerManagerInternal mPowerManagerInternal;
 
     class InjectorForTest extends DeviceIdleController.Injector {
         ConnectivityService connectivityService;
@@ -204,12 +207,15 @@
                 .when(() -> LocalServices.getService(ActivityManagerInternal.class));
         doReturn(mock(ActivityTaskManagerInternal.class))
                 .when(() -> LocalServices.getService(ActivityTaskManagerInternal.class));
-        doReturn(mock(PowerManagerInternal.class))
+        doReturn(mPowerManagerInternal)
                 .when(() -> LocalServices.getService(PowerManagerInternal.class));
+        when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn(
+                mock(PowerSaveState.class));
         doReturn(mock(NetworkPolicyManagerInternal.class))
                 .when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class));
         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
         doNothing().when(mWakeLock).acquire();
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
         mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
         mAnyMotionDetector = new AnyMotionDetectorForTest();
         mInjector = new InjectorForTest(getContext());
@@ -336,6 +342,28 @@
     }
 
     @Test
+    public void testUpdateQuickDozeFlagLocked() {
+        mDeviceIdleController.updateQuickDozeFlagLocked(false);
+        assertFalse(mDeviceIdleController.isQuickDozeEnabled());
+
+        // Make sure setting false when quick doze is already off doesn't change anything.
+        mDeviceIdleController.updateQuickDozeFlagLocked(false);
+        assertFalse(mDeviceIdleController.isQuickDozeEnabled());
+
+        // Test changing from quick doze off to quick doze on.
+        mDeviceIdleController.updateQuickDozeFlagLocked(true);
+        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
+
+        // Make sure setting true when quick doze is already on doesn't change anything.
+        mDeviceIdleController.updateQuickDozeFlagLocked(true);
+        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
+
+        // Test changing from quick doze on to quick doze off.
+        mDeviceIdleController.updateQuickDozeFlagLocked(false);
+        assertFalse(mDeviceIdleController.isQuickDozeEnabled());
+    }
+
+    @Test
     public void testStateActiveToStateInactive_ConditionsNotMet() {
         mDeviceIdleController.becomeActiveLocked("testing", 0);
         verifyStateConditions(STATE_ACTIVE);
@@ -416,6 +444,46 @@
     }
 
     @Test
+    public void testTransitionFromAnyStateToStateQuickDozeDelay() {
+        enterDeepState(STATE_ACTIVE);
+        setQuickDozeEnabled(true);
+        setChargingOn(false);
+        setScreenOn(false);
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_INACTIVE);
+        setQuickDozeEnabled(true);
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_IDLE_PENDING);
+        setQuickDozeEnabled(true);
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_SENSING);
+        setQuickDozeEnabled(true);
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_LOCATING);
+        setQuickDozeEnabled(true);
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        // IDLE should stay as IDLE.
+        enterDeepState(STATE_IDLE);
+        setQuickDozeEnabled(true);
+        verifyStateConditions(STATE_IDLE);
+
+        // IDLE_MAINTENANCE should stay as IDLE_MAINTENANCE.
+        enterDeepState(STATE_IDLE_MAINTENANCE);
+        setQuickDozeEnabled(true);
+        verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+    }
+
+    @Test
     public void testStepIdleStateLocked_InvalidStates() {
         mDeviceIdleController.becomeActiveLocked("testing", 0);
         mDeviceIdleController.stepIdleStateLocked("testing");
@@ -425,49 +493,77 @@
     }
 
     @Test
+    public void testStepIdleStateLocked_ValidStates_QuickDoze() {
+        setAlarmSoon(false);
+
+        // Quick doze should go directly into IDLE.
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.stepIdleStateLocked("testing");
+        verifyStateConditions(STATE_IDLE);
+
+        // Should just alternate between IDLE and IDLE_MAINTENANCE now.
+
+        mDeviceIdleController.stepIdleStateLocked("testing");
+        verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+        mDeviceIdleController.stepIdleStateLocked("testing");
+        verifyStateConditions(STATE_IDLE);
+
+        mDeviceIdleController.stepIdleStateLocked("testing");
+        verifyStateConditions(STATE_IDLE_MAINTENANCE);
+    }
+
+    @Test
     public void testStepIdleStateLocked_ValidStates_WithWakeFromIdleAlarmSoon() {
         enterDeepState(STATE_ACTIVE);
         // Return that there's an alarm coming soon.
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_ACTIVE);
 
         // Everything besides ACTIVE should end up as INACTIVE since the screen would be off.
 
         enterDeepState(STATE_INACTIVE);
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_IDLE_PENDING);
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_SENSING);
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_LOCATING);
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
+        mDeviceIdleController.stepIdleStateLocked("testing");
+        verifyStateConditions(STATE_INACTIVE);
+
+        // With quick doze enabled, we should end up in QUICK_DOZE_DELAY instead of INACTIVE.
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(true);
+        setAlarmSoon(true);
+        mDeviceIdleController.stepIdleStateLocked("testing");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        // With quick doze disabled, we should end up in INACTIVE instead of QUICK_DOZE_DELAY.
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(false);
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_IDLE);
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_IDLE_MAINTENANCE);
-        doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
-                mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(true);
         mDeviceIdleController.stepIdleStateLocked("testing");
         verifyStateConditions(STATE_INACTIVE);
     }
@@ -476,7 +572,7 @@
     public void testStepIdleStateLocked_ValidStates_NoLocationManager() {
         mInjector.locationManager = null;
         // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
-        doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(false);
         // Set state to INACTIVE.
         mDeviceIdleController.becomeActiveLocked("testing", 0);
         setChargingOn(false);
@@ -508,7 +604,7 @@
     @Test
     public void testStepIdleStateLocked_ValidStates_WithLocationManager_NoProviders() {
         // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
-        doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(false);
         // Set state to INACTIVE.
         mDeviceIdleController.becomeActiveLocked("testing", 0);
         setChargingOn(false);
@@ -543,7 +639,7 @@
         mInjector.locationManager = mLocationManager;
         doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
         // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
-        doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
+        setAlarmSoon(false);
         // Set state to INACTIVE.
         mDeviceIdleController.becomeActiveLocked("testing", 0);
         setChargingOn(false);
@@ -729,6 +825,8 @@
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
     }
 
+    ///////////////// EXIT conditions ///////////////////
+
     @Test
     public void testExitMaintenanceEarlyIfNeededLocked_deep_noActiveOps() {
         mDeviceIdleController.setJobsActive(false);
@@ -766,6 +864,10 @@
         mDeviceIdleController.setActiveIdleOpsForTest(0);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyStateConditions(STATE_IDLE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
     }
 
     @Test
@@ -803,6 +905,10 @@
         enterDeepState(STATE_IDLE_MAINTENANCE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
     }
 
     @Test
@@ -840,6 +946,10 @@
         enterDeepState(STATE_IDLE_MAINTENANCE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
     }
 
     @Test
@@ -877,6 +987,10 @@
         enterDeepState(STATE_IDLE_MAINTENANCE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyStateConditions(STATE_IDLE_MAINTENANCE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
     }
 
     @Test
@@ -1030,36 +1144,97 @@
     }
 
     @Test
-    public void testHandleMotionDetectedLocked_deep() {
+    public void testHandleMotionDetectedLocked_deep_quickDoze_off() {
         enterDeepState(STATE_ACTIVE);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_ACTIVE);
 
         // Anything that wasn't ACTIVE before motion detection should end up in the INACTIVE state.
 
         enterDeepState(STATE_INACTIVE);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_IDLE_PENDING);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_SENSING);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_LOCATING);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_IDLE);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_INACTIVE);
 
         enterDeepState(STATE_IDLE_MAINTENANCE);
+        setQuickDozeEnabled(false);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyStateConditions(STATE_INACTIVE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(false);
+        // Disabling quick doze doesn't immediately change the state as coming out is harder than
+        // going in.
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_INACTIVE);
+    }
+
+    @Test
+    public void testHandleMotionDetectedLocked_deep_quickDoze_on() {
+        enterDeepState(STATE_ACTIVE);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_ACTIVE);
+
+        // Anything that wasn't ACTIVE before motion detection should end up in the
+        // QUICK_DOZE_DELAY state since quick doze is enabled.
+
+        enterDeepState(STATE_INACTIVE);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_IDLE_PENDING);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_SENSING);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_LOCATING);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_IDLE);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_IDLE_MAINTENANCE);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(true);
+        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
     }
 
     @Test
@@ -1128,6 +1303,10 @@
         enterDeepState(STATE_IDLE_MAINTENANCE);
         mDeviceIdleController.becomeActiveLocked("test", 1000);
         verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        mDeviceIdleController.becomeActiveLocked("test", 1000);
+        verifyStateConditions(STATE_ACTIVE);
     }
 
     @Test
@@ -1169,6 +1348,14 @@
                 setScreenOn(true);
                 mDeviceIdleController.becomeActiveLocked("testing", 0);
                 break;
+            case STATE_QUICK_DOZE_DELAY:
+                // Start off from ACTIVE in case we're already past the desired state.
+                enterDeepState(STATE_ACTIVE);
+                setQuickDozeEnabled(true);
+                setScreenOn(false);
+                setChargingOn(false);
+                mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+                break;
             case STATE_LOCATING:
                 mInjector.locationManager = mLocationManager;
                 doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(
@@ -1180,8 +1367,11 @@
             case STATE_IDLE_MAINTENANCE:
                 // Make sure the controller doesn't think there's a wake-from-idle alarm coming
                 // soon.
-                doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
+                setAlarmSoon(false);
             case STATE_INACTIVE:
+                // Start off from ACTIVE in case we're already past the desired state.
+                enterDeepState(STATE_ACTIVE);
+                setQuickDozeEnabled(false);
                 setScreenOn(false);
                 setChargingOn(false);
                 mDeviceIdleController.becomeInactiveIfAppropriateLocked();
@@ -1211,6 +1401,8 @@
             case LIGHT_STATE_INACTIVE:
             case LIGHT_STATE_IDLE:
             case LIGHT_STATE_IDLE_MAINTENANCE:
+                // Start off from ACTIVE in case we're already past the desired state.
+                enterLightState(LIGHT_STATE_ACTIVE);
                 setScreenOn(false);
                 setChargingOn(false);
                 int count = 0;
@@ -1256,6 +1448,19 @@
         mDeviceIdleController.updateConnectivityState(null);
     }
 
+    private void setQuickDozeEnabled(boolean on) {
+        mDeviceIdleController.updateQuickDozeFlagLocked(on);
+    }
+
+    private void setAlarmSoon(boolean isSoon) {
+        if (isSoon) {
+            doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+                    mAlarmManager).getNextWakeFromIdleTime();
+        } else {
+            doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
+        }
+    }
+
     private void verifyStateConditions(int expectedState) {
         int curState = mDeviceIdleController.getState();
         assertEquals(
@@ -1292,7 +1497,9 @@
                 assertFalse(mDeviceIdleController.isScreenOn());
                 break;
             case STATE_IDLE:
-                assertTrue(mDeviceIdleController.mMotionListener.isActive());
+                assertTrue(mDeviceIdleController.mMotionListener.isActive()
+                        // If quick doze is enabled, the motion listener should NOT be active.
+                        || mDeviceIdleController.isQuickDozeEnabled());
                 assertFalse(mAnyMotionDetector.isMonitoring);
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn());
@@ -1300,7 +1507,16 @@
                 verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
                 break;
             case STATE_IDLE_MAINTENANCE:
-                assertTrue(mDeviceIdleController.mMotionListener.isActive());
+                assertTrue(mDeviceIdleController.mMotionListener.isActive()
+                        // If quick doze is enabled, the motion listener should NOT be active.
+                        || mDeviceIdleController.isQuickDozeEnabled());
+                assertFalse(mAnyMotionDetector.isMonitoring);
+                assertFalse(mDeviceIdleController.isCharging());
+                assertFalse(mDeviceIdleController.isScreenOn());
+                break;
+            case STATE_QUICK_DOZE_DELAY:
+                // If quick doze is enabled, the motion listener should NOT be active.
+                assertFalse(mDeviceIdleController.mMotionListener.isActive());
                 assertFalse(mAnyMotionDetector.isMonitoring);
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PersistentConnectionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PersistentConnectionTest.java
index 26e77eb..8f39b4a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PersistentConnectionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PersistentConnectionTest.java
@@ -32,9 +32,10 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+
 import org.mockito.ArgumentMatchers;
 
 import java.util.ArrayList;
@@ -44,7 +45,7 @@
 @SmallTest
 public class PersistentConnectionTest extends AndroidTestCase {
     private static final String TAG = "PersistentConnectionTest";
-    
+
     private static class MyConnection extends PersistentConnection<IDeviceAdminService> {
         public long uptimeMillis = 12345;
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 9a7488e..8c27e25 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -133,7 +133,7 @@
 
     private UidRecord addActiveUidRecord(int uid, long curProcStateSeq,
             long lastNetworkUpdatedProcStateSeq) {
-        final UidRecord record = new UidRecord(uid);
+        final UidRecord record = new UidRecord(uid, null /* atmInternal */);
         record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
         record.curProcStateSeq = curProcStateSeq;
         record.waitingForNetwork = true;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index f42f5b1..349c0a37 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -255,7 +255,7 @@
     }
 
     private UidRecord addUidRecord(int uid) {
-        final UidRecord uidRec = new UidRecord(uid);
+        final UidRecord uidRec = new UidRecord(uid, null /* atmInternal */);
         uidRec.waitingForNetwork = true;
         uidRec.hasInternetPermission = true;
         mAms.mActiveUids.put(uid, uidRec);
@@ -274,7 +274,7 @@
         thread.startAndWait("Unexpected state for " + uidRec);
 
         uidRec.setProcState = prevState;
-        uidRec.curProcState = curState;
+        uidRec.setCurProcState(curState);
         mAms.incrementProcStateSeqAndNotifyAppsLocked();
 
         assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter);
@@ -301,7 +301,7 @@
 
     @Test
     public void testBlockStateForUid() {
-        final UidRecord uidRec = new UidRecord(TEST_UID);
+        final UidRecord uidRec = new UidRecord(TEST_UID, null /* atmInternal */);
         int expectedBlockState;
 
         final String errorTemplate = "Block state should be %s, prevState: %s, curState: %s";
@@ -309,47 +309,48 @@
             return String.format(errorTemplate,
                     valueToString(ActivityManagerService.class, "NETWORK_STATE_", blockState),
                     valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.setProcState),
-                    valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.curProcState));
+                    valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.getCurProcState())
+            );
         };
 
         // No change in uid state
         uidRec.setProcState = PROCESS_STATE_RECEIVER;
-        uidRec.curProcState = PROCESS_STATE_RECEIVER;
+        uidRec.setCurProcState(PROCESS_STATE_RECEIVER);
         expectedBlockState = NETWORK_STATE_NO_CHANGE;
         assertEquals(errorMsg.apply(expectedBlockState),
                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
 
         // Foreground to foreground
         uidRec.setProcState = PROCESS_STATE_FOREGROUND_SERVICE;
-        uidRec.curProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+        uidRec.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
         expectedBlockState = NETWORK_STATE_NO_CHANGE;
         assertEquals(errorMsg.apply(expectedBlockState),
                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
 
         // Background to background
         uidRec.setProcState = PROCESS_STATE_CACHED_ACTIVITY;
-        uidRec.curProcState = PROCESS_STATE_CACHED_EMPTY;
+        uidRec.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
         expectedBlockState = NETWORK_STATE_NO_CHANGE;
         assertEquals(errorMsg.apply(expectedBlockState),
                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
 
         // Background to background
         uidRec.setProcState = PROCESS_STATE_NONEXISTENT;
-        uidRec.curProcState = PROCESS_STATE_CACHED_ACTIVITY;
+        uidRec.setCurProcState(PROCESS_STATE_CACHED_ACTIVITY);
         expectedBlockState = NETWORK_STATE_NO_CHANGE;
         assertEquals(errorMsg.apply(expectedBlockState),
                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
 
         // Background to foreground
         uidRec.setProcState = PROCESS_STATE_SERVICE;
-        uidRec.curProcState = PROCESS_STATE_FOREGROUND_SERVICE;
+        uidRec.setCurProcState(PROCESS_STATE_FOREGROUND_SERVICE);
         expectedBlockState = NETWORK_STATE_BLOCK;
         assertEquals(errorMsg.apply(expectedBlockState),
                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
 
         // Foreground to background
         uidRec.setProcState = PROCESS_STATE_TOP;
-        uidRec.curProcState = PROCESS_STATE_LAST_ACTIVITY;
+        uidRec.setCurProcState(PROCESS_STATE_LAST_ACTIVITY);
         expectedBlockState = NETWORK_STATE_UNBLOCK;
         assertEquals(errorMsg.apply(expectedBlockState),
                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
@@ -593,10 +594,10 @@
                 assertNotNull("validateUidRecord should not be null since the change is neither "
                         + "CHANGE_GONE nor CHANGE_GONE_IDLE", validateUidRecord);
                 assertEquals("processState: " + item.processState + " curProcState: "
-                        + validateUidRecord.curProcState + " should have been equal",
-                        item.processState, validateUidRecord.curProcState);
+                        + validateUidRecord.getCurProcState() + " should have been equal",
+                        item.processState, validateUidRecord.getCurProcState());
                 assertEquals("processState: " + item.processState + " setProcState: "
-                        + validateUidRecord.curProcState + " should have been equal",
+                        + validateUidRecord.getCurProcState() + " should have been equal",
                         item.processState, validateUidRecord.setProcState);
                 if (item.change == UidRecord.CHANGE_IDLE) {
                     assertTrue("UidRecord.idle should be updated to true for CHANGE_IDLE",
@@ -626,7 +627,7 @@
 
     @Test
     public void testEnqueueUidChangeLocked_procStateSeqUpdated() {
-        final UidRecord uidRecord = new UidRecord(TEST_UID);
+        final UidRecord uidRecord = new UidRecord(TEST_UID, null /* atmInternal */);
         uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1;
 
         // Verify with no pending changes for TEST_UID.
@@ -672,7 +673,7 @@
     @MediumTest
     @Test
     public void testEnqueueUidChangeLocked_dispatchUidsChanged() {
-        final UidRecord uidRecord = new UidRecord(TEST_UID);
+        final UidRecord uidRecord = new UidRecord(TEST_UID, null /* atmInternal */);
         final int expectedProcState = PROCESS_STATE_SERVICE;
         uidRecord.setProcState = expectedProcState;
         uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1;
@@ -744,7 +745,7 @@
     private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
             long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq,
             final long procStateSeqToWait, boolean expectWait) throws Exception {
-        final UidRecord record = new UidRecord(Process.myUid());
+        final UidRecord record = new UidRecord(Process.myUid(), null /* atmInternal */);
         record.curProcStateSeq = curProcStateSeq;
         record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq;
         record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index 65e4fa0..270d394 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -109,7 +109,6 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mService.mAm = mAm;
         mService.mAmInternal = mAmInternal;
         mInterceptor = new ActivityStartInterceptor(mService, mSupervisor, mContext);
         mInterceptor.setStates(TEST_USER_ID, TEST_REAL_CALLING_PID, TEST_REAL_CALLING_UID,
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
index d4bab2e..2fb10e1 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
@@ -17,6 +17,8 @@
 package com.android.server.am;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
@@ -189,6 +191,35 @@
     }
 
     /**
+     * Tests preferred display id calculation for VR.
+     */
+    @Test
+    public void testVrPreferredDisplay() {
+        final int vr2dDisplayId = 1;
+        mService.mVr2dDisplayId = vr2dDisplayId;
+
+        final LaunchParams result = new LaunchParams();
+        final ActivityRecord vrActivity = new ActivityBuilder(mService).build();
+        vrActivity.requestedVrComponent = vrActivity.realActivity;
+
+        // VR activities should always land on default display.
+        mController.calculate(null /*task*/, null /*layout*/, vrActivity /*activity*/,
+                null /*source*/, null /*options*/, result);
+        assertEquals(DEFAULT_DISPLAY, result.mPreferredDisplayId);
+
+        // Otherwise, always lands on VR 2D display.
+        final ActivityRecord vr2dActivity = new ActivityBuilder(mService).build();
+        mController.calculate(null /*task*/, null /*layout*/, vr2dActivity /*activity*/,
+                null /*source*/, null /*options*/, result);
+        assertEquals(vr2dDisplayId, result.mPreferredDisplayId);
+        mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
+                null /*options*/, result);
+        assertEquals(vr2dDisplayId, result.mPreferredDisplayId);
+
+        mService.mVr2dDisplayId = INVALID_DISPLAY;
+    }
+
+    /**
      * Ensures that {@link LaunchParamsModifier} requests specifying display id during
      * layout are honored.
      */
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
new file mode 100644
index 0000000..0328621
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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.inputmethod;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodManagerServiceTests {
+    static final int SYSTEM_DECORATION_SUPPORT_DISPLAY_ID = 2;
+    static final int NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID = 3;
+
+    static InputMethodManagerService.ImeDisplayValidator sChecker =
+            (displayId) -> {
+                switch (displayId) {
+                    case SYSTEM_DECORATION_SUPPORT_DISPLAY_ID:
+                        return true;
+                    case NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID:
+                        return false;
+                    default:
+                        throw new IllegalArgumentException("Unknown displayId=" + displayId);
+                }
+            };
+
+    static InputMethodManagerService.ImeDisplayValidator sMustNotBeCalledChecker =
+            (displayId) -> {
+                fail("Should not pass to display config check for this test case.");
+                return false;
+            };
+
+    @Test
+    public void testComputeImeDisplayId_defaultDisplayId() {
+        // Make sure that there is a short-circuit for DEFAULT_DISPLAY.
+        assertEquals(DEFAULT_DISPLAY,
+                InputMethodManagerService.computeImeDisplayIdForTarget(
+                        DEFAULT_DISPLAY, false /* isVrImeStarted */,
+                        sMustNotBeCalledChecker));
+    }
+
+    @Test
+    public void testComputeImeDisplayId_InvalidDisplayId() {
+        // Make sure that there is a short-circuit for INVALID_DISPLAY.
+        assertEquals(DEFAULT_DISPLAY,
+                InputMethodManagerService.computeImeDisplayIdForTarget(
+                        INVALID_DISPLAY, false /* isVrImeStarted */,
+                        sMustNotBeCalledChecker));
+    }
+
+    @Test
+    public void testComputeImeDisplayId_VrIme() {
+        // Make sure that there is a short-circuit for VR IME.
+        assertEquals(DEFAULT_DISPLAY,
+                InputMethodManagerService.computeImeDisplayIdForTarget(
+                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, true /* isVrImeStarted */,
+                        sMustNotBeCalledChecker));
+    }
+
+    @Test
+    public void testComputeImeDisplayId_noSystemDecorationSupportDisplay() {
+        // Presume display didn't support system decoration.
+        // Make sure IME displayId is DEFAULT_DISPLAY.
+        assertEquals(DEFAULT_DISPLAY,
+                InputMethodManagerService.computeImeDisplayIdForTarget(
+                        NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, false /* isVrImeStarted */,
+                        sChecker));
+    }
+
+    @Test
+    public void testComputeImeDisplayId_withSystemDecorationSupportDisplay() {
+        // Presume display support system decoration.
+        // Make sure IME displayId is the same display.
+        assertEquals(SYSTEM_DECORATION_SUPPORT_DISPLAY_ID,
+                InputMethodManagerService.computeImeDisplayIdForTarget(
+                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, false /* isVrImeStarted */,
+                        sChecker));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index bd4a356..77f6a23 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -58,7 +58,8 @@
             + "adjust_brightness_factor=0.7,"
             + "fullbackup_deferred=true,"
             + "keyvaluebackup_deferred=false,"
-            + "gps_mode=0";
+            + "gps_mode=0,"
+            + "quick_doze_enabled=true";
     private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
 
     private class BatterySaverPolicyForTest extends BatterySaverPolicy {
@@ -102,48 +103,48 @@
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyNull_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.NULL);
+        testServiceDefaultValue_On(ServiceType.NULL);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.VIBRATION);
+        testServiceDefaultValue_On(ServiceType.VIBRATION);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
         mBatterySaverPolicy.setAccessibilityEnabledForTest(true);
-        testServiceDefaultValue_unchanged(ServiceType.VIBRATION);
+        testServiceDefaultValue_Off(ServiceType.VIBRATION);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.SOUND);
+        testServiceDefaultValue_On(ServiceType.SOUND);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyFullBackup_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.FULL_BACKUP);
+        testServiceDefaultValue_On(ServiceType.FULL_BACKUP);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyKeyValueBackup_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.KEYVALUE_BACKUP);
+        testServiceDefaultValue_On(ServiceType.KEYVALUE_BACKUP);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
-        testServiceDefaultValue_unchanged(ServiceType.ANIMATION);
+        testServiceDefaultValue_Off(ServiceType.ANIMATION);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyBatteryStats_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.BATTERY_STATS);
+        testServiceDefaultValue_On(ServiceType.BATTERY_STATS);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyNetworkFirewall_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.NETWORK_FIREWALL);
+        testServiceDefaultValue_On(ServiceType.NETWORK_FIREWALL);
     }
 
     @SmallTest
@@ -160,12 +161,12 @@
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
-        testServiceDefaultValue_unchanged(ServiceType.SCREEN_BRIGHTNESS);
+        testServiceDefaultValue_Off(ServiceType.SCREEN_BRIGHTNESS);
     }
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyGps_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.GPS);
+        testServiceDefaultValue_On(ServiceType.GPS);
 
         PowerSaveState stateOn =
                 mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, true);
@@ -173,6 +174,11 @@
     }
 
     @SmallTest
+    public void testGetBatterySaverPolicy_PolicyQuickDoze_DefaultValueCorrect() {
+        testServiceDefaultValue_Off(ServiceType.QUICK_DOZE);
+    }
+
+    @SmallTest
     public void testUpdateConstants_getCorrectData() {
         mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, "");
 
@@ -214,6 +220,10 @@
                 mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, BATTERY_SAVER_ON);
         assertThat(gpsState.batterySaverEnabled).isTrue();
         assertThat(gpsState.gpsMode).isEqualTo(GPS_MODE);
+
+        final PowerSaveState quickDozeState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.QUICK_DOZE, BATTERY_SAVER_ON);
+        assertThat(quickDozeState.batterySaverEnabled).isTrue();
     }
 
     @SmallTest
@@ -223,7 +233,7 @@
         mBatterySaverPolicy.updateConstantsLocked(null, "");
     }
 
-    private void testServiceDefaultValue(@ServiceType int type) {
+    private void testServiceDefaultValue_On(@ServiceType int type) {
         mBatterySaverPolicy.updateConstantsLocked("", "");
         final PowerSaveState batterySaverStateOn =
                 mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
@@ -234,7 +244,7 @@
         assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
     }
 
-    private void testServiceDefaultValue_unchanged(@ServiceType int type) {
+    private void testServiceDefaultValue_Off(@ServiceType int type) {
         mBatterySaverPolicy.updateConstantsLocked("", "");
         final PowerSaveState batterySaverStateOn =
                 mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 5a787ec..473682d 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -51,6 +51,10 @@
     private IntervalStats mIntervalStats = new IntervalStats();
     private long mEndTime = 0;
 
+    // Key under which the payload blob is stored
+    // same as UsageStatsBackupHelper.KEY_USAGE_STATS
+    static final String KEY_USAGE_STATS = "usage_stats";
+
     private static final UsageStatsDatabase.StatCombiner<IntervalStats> mIntervalStatsVerifier =
             new UsageStatsDatabase.StatCombiner<IntervalStats>() {
                 @Override
@@ -104,10 +108,11 @@
 
     private void populateIntervalStats() {
         final int numberOfEvents = 3000;
-        long time = 1;
+        final int timeProgression = 23;
+        long time = System.currentTimeMillis() - (numberOfEvents*timeProgression);
         mIntervalStats = new IntervalStats();
 
-        mIntervalStats.beginTime = 1;
+        mIntervalStats.beginTime = time;
         mIntervalStats.interactiveTracker.count = 2;
         mIntervalStats.interactiveTracker.duration = 111111;
         mIntervalStats.nonInteractiveTracker.count = 3;
@@ -158,7 +163,7 @@
             mIntervalStats.events.insert(event);
             mIntervalStats.update(event.mPackage, event.mTimeStamp, event.mEventType);
 
-            time += 23; // Arbitrary progression of time
+            time += timeProgression; // Arbitrary progression of time
         }
         mEndTime = time;
 
@@ -286,9 +291,19 @@
         }
         assertEquals(stats1.activeConfiguration, stats2.activeConfiguration);
 
-        assertEquals(stats1.events.size(), stats2.events.size());
-        for (int i = 0; i < stats1.events.size(); i++) {
-            compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i);
+        if (stats1.events == null) {
+            // If stats1 events are null, stats2 should be null or empty
+            if (stats2.events != null) {
+                assertEquals(stats2.events.size(), 0);
+            }
+        } else if (stats2.events == null) {
+            // If stats2 events are null, stats1 should be null or empty
+            assertEquals(stats1.events.size(), 0);
+        } else {
+            assertEquals(stats1.events.size(), stats2.events.size());
+            for (int i = 0; i < stats1.events.size(); i++) {
+                compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i);
+            }
         }
     }
 
@@ -340,6 +355,47 @@
     }
 
     /**
+     * Runs the Backup and Restore tests.
+     * Will write the generated IntervalStat to a database and create a backup in the specified
+     * version's format. The database will then be restored from the blob and the restored
+     * interval stats will be compared to the generated stats.
+     */
+    void runBackupRestoreTest(int version) throws IOException {
+        UsageStatsDatabase prevDB = new UsageStatsDatabase(mTestDir);
+        prevDB.init(1);
+        prevDB.putUsageStats(UsageStatsManager.INTERVAL_DAILY, mIntervalStats);
+        // Create a backup with a specific version
+        byte[] blob = prevDB.getBackupPayload(KEY_USAGE_STATS, version);
+
+        clearUsageStatsFiles();
+
+        UsageStatsDatabase newDB = new UsageStatsDatabase(mTestDir);
+        newDB.init(1);
+        // Attempt to restore the usage stats from the backup
+        newDB.applyRestoredPayload(KEY_USAGE_STATS, blob);
+        List<IntervalStats> stats = newDB.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, 0, mEndTime,
+                mIntervalStatsVerifier);
+
+
+        if (version > newDB.BACKUP_VERSION || version < 1) {
+            if (stats != null && stats.size() != 0) {
+                fail("UsageStatsDatabase should ne be able to restore from unknown data versions");
+            }
+            return;
+        }
+
+        assertEquals(1, stats.size());
+
+        // Clear non backed up data from expected IntervalStats
+        mIntervalStats.activeConfiguration = null;
+        mIntervalStats.configurations.clear();
+        if (mIntervalStats.events != null) mIntervalStats.events.clear();
+
+        // The written and read IntervalStats should match
+        compareIntervalStats(mIntervalStats, stats.get(0));
+    }
+
+    /**
      * Test the version upgrade from 3 to 4
      */
     @Test
@@ -349,4 +405,18 @@
         runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_MONTHLY);
         runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_YEARLY);
     }
+
+
+    /**
+     * Test the version upgrade from 3 to 4
+     */
+    @Test
+    public void testBackupRestore() throws IOException {
+        runBackupRestoreTest(1);
+        runBackupRestoreTest(4);
+
+        // test invalid backup versions as well
+        runBackupRestoreTest(0);
+        runBackupRestoreTest(99999);
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 8946d25..0e15947 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -58,31 +58,31 @@
  * When the UsageStatsDatabase version is upgraded, the files on disk are migrated to the new
  * version on init. The steps of migration are as follows:
  * 1) Check if version upgrade breadcrumb exists on disk, if so skip to step 4.
- * 2) Copy current files to versioned backup files.
- * 3) Write a temporary breadcrumb file with some info about the backed up files.
- * 4) Deserialize a versioned backup file using the info written to the breadcrumb for the
- * correct deserialization methodology.
+ * 2) Move current files to a timestamped backup directory.
+ * 3) Write a temporary breadcrumb file with some info about the backup directory.
+ * 4) Deserialize the backup files in the timestamped backup folder referenced by the breadcrumb.
  * 5) Reserialize the data read from the file with the new version format and replace the old files
- * 6) Repeat Step 3 and 4 for each versioned backup file matching the breadcrumb file.
+ * 6) Repeat Step 3 and 4 for each file in the backup folder.
  * 7) Update the version file with the new version and build fingerprint.
- * 8) Delete the versioned backup files (unless flagged to be kept).
+ * 8) Delete the time stamped backup folder (unless flagged to be kept).
  * 9) Delete the breadcrumb file.
  *
  * Performing the upgrade steps in this order, protects against unexpected shutdowns mid upgrade
  *
- * A versioned backup file is simply a copy of a Usage Stats file with some extra info embedded in
- * the file name. The structure of the versioned backup filename is as followed:
- * (original file name).(backup timestamp).(original file version).vak
- *
- * During the version upgrade process, the new upgraded file will have it's name set to the original
- * file name. The backup timestamp helps distinguish between versioned backups if multiple upgrades
- * and downgrades have taken place. The original file version denotes how to parse the file.
+ * The backup directory will contain directories with timestamp names. If the upgrade breadcrumb
+ * exists on disk, it will contain a timestamp which will match one of the backup directories. The
+ * breadcrumb will also contain a version number which will denote how the files in the backup
+ * directory should be deserialized.
  */
 public class UsageStatsDatabase {
-    private static final int DEFAULT_CURRENT_VERSION = 3;
-
-    // Current version of the backup schema
-    static final int BACKUP_VERSION = 1;
+    private static final int DEFAULT_CURRENT_VERSION = 4;
+    /**
+     * Current version of the backup schema
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static final int BACKUP_VERSION = 4;
 
     // Key under which the payload blob is stored
     // same as UsageStatsBackupHelper.KEY_USAGE_STATS
@@ -91,13 +91,12 @@
     // Persist versioned backup files.
     // Should be false, except when testing new versions
     // STOPSHIP: b/111422946 this should be false on launch
-    static final boolean KEEP_VAK_FILES = true;
+    static final boolean KEEP_BACKUP_DIR = true;
 
     private static final String TAG = "UsageStatsDatabase";
     // STOPSHIP: b/111422946 this should be boolean DEBUG = UsageStatsService.DEBUG; on launch
     private static final boolean DEBUG = true;
     private static final String BAK_SUFFIX = ".bak";
-    private static final String VERSIONED_BAK_SUFFIX = ".vak";
     private static final String CHECKED_IN_SUFFIX = UsageStatsXml.CHECKED_IN_SUFFIX;
     private static final String RETENTION_LEN_KEY = "ro.usagestats.chooser.retention";
     private static final int SELECTION_LOG_RETENTION_LEN =
@@ -108,12 +107,13 @@
     private final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
     private final UnixCalendar mCal;
     private final File mVersionFile;
+    private final File mBackupsDir;
     // If this file exists on disk, UsageStatsDatabase is in the middle of migrating files to a new
     // version. If this file exists on boot, the upgrade was interrupted and needs to be picked up
     // where it left off.
     private final File mUpdateBreadcrumb;
     // Current version of the database files schema
-    private final int mCurrentVersion;
+    private int mCurrentVersion;
     private boolean mFirstUpdate;
     private boolean mNewUpdate;
 
@@ -133,6 +133,7 @@
         };
         mCurrentVersion = version;
         mVersionFile = new File(dir, "version");
+        mBackupsDir = new File(dir, "backups");
         mUpdateBreadcrumb = new File(dir, "breadcrumb");
         mSortedStatFiles = new TimeSparseArray[mIntervalDirs.length];
         mCal = new UnixCalendar(0);
@@ -251,7 +252,7 @@
         final FilenameFilter backupFileFilter = new FilenameFilter() {
             @Override
             public boolean accept(File dir, String name) {
-                return !name.endsWith(BAK_SUFFIX) && !name.endsWith(VERSIONED_BAK_SUFFIX);
+                return !name.endsWith(BAK_SUFFIX);
             }
         };
 
@@ -316,24 +317,33 @@
         if (version != mCurrentVersion) {
             Slog.i(TAG, "Upgrading from version " + version + " to " + mCurrentVersion);
             if (!mUpdateBreadcrumb.exists()) {
-                doUpgradeLocked(version);
+                try {
+                    doUpgradeLocked(version);
+                } catch (Exception e) {
+                    Slog.e(TAG,
+                            "Failed to upgrade from version " + version + " to " + mCurrentVersion,
+                            e);
+                    // Fallback to previous version.
+                    mCurrentVersion = version;
+                    return;
+                }
             } else {
                 Slog.i(TAG, "Version upgrade breadcrumb found on disk! Continuing version upgrade");
             }
+        }
 
-            if (mUpdateBreadcrumb.exists()) {
-                int previousVersion;
-                long token;
-                try (BufferedReader reader = new BufferedReader(
-                        new FileReader(mUpdateBreadcrumb))) {
-                    token = Long.parseLong(reader.readLine());
-                    previousVersion = Integer.parseInt(reader.readLine());
-                } catch (NumberFormatException | IOException e) {
-                    Slog.e(TAG, "Failed read version upgrade breadcrumb");
-                    throw new RuntimeException(e);
-                }
-                continueUpgradeLocked(previousVersion, token);
+        if (mUpdateBreadcrumb.exists()) {
+            int previousVersion;
+            long token;
+            try (BufferedReader reader = new BufferedReader(
+                    new FileReader(mUpdateBreadcrumb))) {
+                token = Long.parseLong(reader.readLine());
+                previousVersion = Integer.parseInt(reader.readLine());
+            } catch (NumberFormatException | IOException e) {
+                Slog.e(TAG, "Failed read version upgrade breadcrumb");
+                throw new RuntimeException(e);
             }
+            continueUpgradeLocked(previousVersion, token);
         }
 
         if (version != mCurrentVersion || mNewUpdate) {
@@ -351,11 +361,12 @@
 
         if (mUpdateBreadcrumb.exists()) {
             // Files should be up to date with current version. Clear the version update breadcrumb
-            if (!KEEP_VAK_FILES) {
-                removeVersionedBackupFiles();
-            }
             mUpdateBreadcrumb.delete();
         }
+
+        if (mBackupsDir.exists() && !KEEP_BACKUP_DIR) {
+            deleteDirectory(mBackupsDir);
+        }
     }
 
     private String getBuildFingerprint() {
@@ -378,22 +389,36 @@
                 }
             }
         } else {
-            // Turn all current usage stats files into versioned backup files
+            // Create a dir in backups based on current timestamp
             final long token = System.currentTimeMillis();
-            final FilenameFilter backupFileFilter = new FilenameFilter() {
-                @Override
-                public boolean accept(File dir, String name) {
-                    return !name.endsWith(BAK_SUFFIX) && !name.endsWith(VERSIONED_BAK_SUFFIX);
-                }
-            };
+            final File backupDir = new File(mBackupsDir, Long.toString(token));
+            backupDir.mkdirs();
+            if (!backupDir.exists()) {
+                throw new IllegalStateException(
+                        "Failed to create backup directory " + backupDir.getAbsolutePath());
+            }
+            try {
+                Files.copy(mVersionFile.toPath(),
+                        new File(backupDir, mVersionFile.getName()).toPath(),
+                        StandardCopyOption.REPLACE_EXISTING);
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to back up version file : " + mVersionFile.toString());
+                throw new RuntimeException(e);
+            }
 
             for (int i = 0; i < mIntervalDirs.length; i++) {
-                File[] files = mIntervalDirs[i].listFiles(backupFileFilter);
+                final File backupIntervalDir = new File(backupDir, mIntervalDirs[i].getName());
+                backupIntervalDir.mkdir();
+
+                if (!backupIntervalDir.exists()) {
+                    throw new IllegalStateException(
+                            "Failed to create interval backup directory "
+                                    + backupIntervalDir.getAbsolutePath());
+                }
+                File[] files = mIntervalDirs[i].listFiles();
                 if (files != null) {
                     for (int j = 0; j < files.length; j++) {
-                        final File backupFile = new File(
-                                files[j].toString() + "." + Long.toString(token) + "."
-                                        + Integer.toString(thisVersion) + VERSIONED_BAK_SUFFIX);
+                        final File backupFile = new File(backupIntervalDir, files[j].getName());
                         if (DEBUG) {
                             Slog.d(TAG, "Creating versioned (" + Integer.toString(thisVersion)
                                     + ") backup of " + files[j].toString()
@@ -403,9 +428,8 @@
 
                         try {
                             // Backup file should not already exist, but make sure it doesn't
-                            Files.deleteIfExists(backupFile.toPath());
                             Files.move(files[j].toPath(), backupFile.toPath(),
-                                    StandardCopyOption.ATOMIC_MOVE);
+                                    StandardCopyOption.REPLACE_EXISTING);
                         } catch (IOException e) {
                             Slog.e(TAG, "Failed to back up file : " + files[j].toString());
                             throw new RuntimeException(e);
@@ -414,8 +438,7 @@
                 }
             }
 
-            // Leave a breadcrumb behind noting that all the usage stats have been copied to a
-            // versioned backup.
+            // Leave a breadcrumb behind noting that all the usage stats have been moved to a backup
             BufferedWriter writer = null;
             try {
                 writer = new BufferedWriter(new FileWriter(mUpdateBreadcrumb));
@@ -434,18 +457,13 @@
     }
 
     private void continueUpgradeLocked(int version, long token) {
-        // Read all the backed ups for the specified version and rewrite them with the current
-        // version's file format.
-        final FilenameFilter versionedBackupFileFilter = new FilenameFilter() {
-            @Override
-            public boolean accept(File dir, String name) {
-                return name.endsWith("." + Long.toString(token) + "." + Integer.toString(version)
-                        + VERSIONED_BAK_SUFFIX);
-            }
-        };
+        final File backupDir = new File(mBackupsDir, Long.toString(token));
 
+        // Read each file in the backup according to the version and write to the interval
+        // directories in the current versions format
         for (int i = 0; i < mIntervalDirs.length; i++) {
-            File[] files = mIntervalDirs[i].listFiles(versionedBackupFileFilter);
+            final File backedUpInterval = new File(backupDir, mIntervalDirs[i].getName());
+            File[] files = backedUpInterval.listFiles();
             if (files != null) {
                 for (int j = 0; j < files.length; j++) {
                     if (DEBUG) {
@@ -459,34 +477,9 @@
                         readLocked(new AtomicFile(files[j]), stats, version);
                         writeLocked(new AtomicFile(new File(mIntervalDirs[i],
                                 Long.toString(stats.beginTime))), stats, mCurrentVersion);
-                    } catch (IOException e) {
-                        Slog.e(TAG,
-                                "Failed to upgrade versioned backup file : " + files[j].toString());
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-        }
-    }
-
-    private void removeVersionedBackupFiles() {
-        final FilenameFilter versionedBackupFileFilter = new FilenameFilter() {
-            @Override
-            public boolean accept(File dir, String name) {
-                return name.endsWith(VERSIONED_BAK_SUFFIX);
-            }
-        };
-
-        for (int i = 0; i < mIntervalDirs.length; i++) {
-            File[] files = mIntervalDirs[i].listFiles(versionedBackupFileFilter);
-            if (files != null) {
-                for (int j = 0; j < files.length; j++) {
-                    if (DEBUG) {
-                        Slog.d(TAG,
-                                "Removing " + files[j].toString() + " for interval " + i);
-                    }
-                    if (!files[j].delete()) {
-                        Slog.e(TAG, "Failed to delete file : " + files[j].toString());
+                    } catch (Exception e) {
+                        // This method is called on boot, log the exception and move on
+                        Slog.e(TAG, "Failed to upgrade backup file : " + files[j].toString());
                     }
                 }
             }
@@ -761,7 +754,7 @@
                             }
                         }
                         writeLocked(af, stats);
-                    } catch (IOException e) {
+                    } catch (Exception e) {
                         Slog.e(TAG, "Failed to delete chooser counts from usage stats file", e);
                     }
                 }
@@ -961,7 +954,7 @@
             sb.append("\nError found in:\n");
             sb.append(file.getBaseFile().getAbsolutePath());
             sb.append("\nPlease go to b/115429334 to help root cause this issue");
-            Slog.wtf(TAG,sb.toString());
+            Slog.wtf(TAG, sb.toString());
         }
     }
 
@@ -1013,40 +1006,53 @@
 
     /* Backup/Restore Code */
     byte[] getBackupPayload(String key) {
+        return getBackupPayload(key, BACKUP_VERSION);
+    }
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public byte[] getBackupPayload(String key, int version) {
         synchronized (mLock) {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             if (KEY_USAGE_STATS.equals(key)) {
                 prune(System.currentTimeMillis());
                 DataOutputStream out = new DataOutputStream(baos);
                 try {
-                    out.writeInt(BACKUP_VERSION);
+                    out.writeInt(version);
 
                     out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size());
+
                     for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size();
                             i++) {
                         writeIntervalStatsToStream(out,
-                                mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].valueAt(i));
+                                mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].valueAt(i),
+                                version);
                     }
 
                     out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size());
                     for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size();
                             i++) {
                         writeIntervalStatsToStream(out,
-                                mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].valueAt(i));
+                                mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].valueAt(i),
+                                version);
                     }
 
                     out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size());
                     for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size();
                             i++) {
                         writeIntervalStatsToStream(out,
-                                mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].valueAt(i));
+                                mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].valueAt(i),
+                                version);
                     }
 
                     out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size());
                     for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size();
                             i++) {
                         writeIntervalStatsToStream(out,
-                                mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].valueAt(i));
+                                mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].valueAt(i),
+                                version);
                     }
                     if (DEBUG) Slog.i(TAG, "Written " + baos.size() + " bytes of data");
                 } catch (IOException ioe) {
@@ -1059,7 +1065,11 @@
 
     }
 
-    void applyRestoredPayload(String key, byte[] payload) {
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public void applyRestoredPayload(String key, byte[] payload) {
         synchronized (mLock) {
             if (KEY_USAGE_STATS.equals(key)) {
                 // Read stats files for the current device configs
@@ -1087,28 +1097,32 @@
 
                     int fileCount = in.readInt();
                     for (int i = 0; i < fileCount; i++) {
-                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in),
+                                backupDataVersion);
                         stats = mergeStats(stats, dailyConfigSource);
                         putUsageStats(UsageStatsManager.INTERVAL_DAILY, stats);
                     }
 
                     fileCount = in.readInt();
                     for (int i = 0; i < fileCount; i++) {
-                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in),
+                                backupDataVersion);
                         stats = mergeStats(stats, weeklyConfigSource);
                         putUsageStats(UsageStatsManager.INTERVAL_WEEKLY, stats);
                     }
 
                     fileCount = in.readInt();
                     for (int i = 0; i < fileCount; i++) {
-                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in),
+                                backupDataVersion);
                         stats = mergeStats(stats, monthlyConfigSource);
                         putUsageStats(UsageStatsManager.INTERVAL_MONTHLY, stats);
                     }
 
                     fileCount = in.readInt();
                     for (int i = 0; i < fileCount; i++) {
-                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in),
+                                backupDataVersion);
                         stats = mergeStats(stats, yearlyConfigSource);
                         putUsageStats(UsageStatsManager.INTERVAL_YEARLY, stats);
                     }
@@ -1135,7 +1149,7 @@
         return beingRestored;
     }
 
-    private void writeIntervalStatsToStream(DataOutputStream out, AtomicFile statsFile)
+    private void writeIntervalStatsToStream(DataOutputStream out, AtomicFile statsFile, int version)
             throws IOException {
         IntervalStats stats = new IntervalStats();
         try {
@@ -1146,7 +1160,7 @@
             return;
         }
         sanitizeIntervalStatsForBackup(stats);
-        byte[] data = serializeIntervalStats(stats);
+        byte[] data = serializeIntervalStats(stats, version);
         out.writeInt(data.length);
         out.write(data);
     }
@@ -1165,26 +1179,26 @@
         if (stats.events != null) stats.events.clear();
     }
 
-    private byte[] serializeIntervalStats(IntervalStats stats) {
+    private byte[] serializeIntervalStats(IntervalStats stats, int version) {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream out = new DataOutputStream(baos);
         try {
             out.writeLong(stats.beginTime);
-            writeLocked(out, stats);
-        } catch (IOException ioe) {
+            writeLocked(out, stats, version);
+        } catch (Exception ioe) {
             Slog.d(TAG, "Serializing IntervalStats Failed", ioe);
             baos.reset();
         }
         return baos.toByteArray();
     }
 
-    private IntervalStats deserializeIntervalStats(byte[] data) {
+    private IntervalStats deserializeIntervalStats(byte[] data, int version) {
         ByteArrayInputStream bais = new ByteArrayInputStream(data);
         DataInputStream in = new DataInputStream(bais);
         IntervalStats stats = new IntervalStats();
         try {
             stats.beginTime = in.readLong();
-            readLocked(in, stats);
+            readLocked(in, stats, version);
         } catch (IOException ioe) {
             Slog.d(TAG, "DeSerializing IntervalStats Failed", ioe);
             stats = null;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index bafb0a2..ad2501d 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -566,6 +566,40 @@
         }
     }
 
+    SoundTrigger.RecognitionEvent getGenericModelState(UUID modelId) {
+        synchronized (mLock) {
+            MetricsLogger.count(mContext, "sth_get_generic_model_state", 1);
+            if (modelId == null || mModule == null) {
+                return null;
+            }
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null || !modelData.isGenericModel()) {
+                Slog.w(TAG, "GetGenericModelState error: Invalid generic model id:" +
+                        modelId);
+                return null;
+            }
+            if (!modelData.isModelLoaded()) {
+                Slog.i(TAG, "GetGenericModelState: Given generic model is not loaded:" + modelId);
+                return null;
+            }
+            if (!modelData.isModelStarted()) {
+                Slog.i(TAG, "GetGenericModelState: Given generic model is not started:" + modelId);
+                return null;
+            }
+
+            SoundTrigger.RecognitionEvent ret = mModule.getModelState(modelData.getHandle());
+            if (ret == null) {
+                Slog.w(TAG, "GetGenericModelState() call failed");
+            }
+            return ret;
+        }
+    }
+
+    SoundTrigger.RecognitionEvent getKeyphraseModelState(UUID modelId) {
+        Slog.w(TAG, "GetKeyphraseModelState error: Not implemented");
+        return null;
+    }
+
     //---- SoundTrigger.StatusListener methods
     @Override
     public void onRecognition(RecognitionEvent event) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 7c22613..d57fcb1 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -434,6 +434,40 @@
             }
             return mSoundTriggerHelper.isRecognitionRequested(parcelUuid.getUuid());
         }
+
+        @Override
+        public SoundTrigger.RecognitionEvent getModelState(ParcelUuid soundModelId) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (!isInitialized()) return null;
+            if (DEBUG) {
+                Slog.i(TAG, "getModelState(): id = " + soundModelId);
+            }
+
+            synchronized (mLock) {
+                SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+                if (soundModel == null) {
+                    Slog.e(TAG, soundModelId + " is not loaded");
+                    return null;
+                }
+                SoundTrigger.RecognitionEvent ret = null;
+                switch (soundModel.type) {
+                    case SoundModel.TYPE_KEYPHRASE:
+                        ret = mSoundTriggerHelper.getKeyphraseModelState(soundModel.uuid);
+                        break;
+                    case SoundModel.TYPE_GENERIC_SOUND:
+                        ret = mSoundTriggerHelper.getGenericModelState(soundModel.uuid);
+                        break;
+                    default:
+                        Slog.e(TAG, "Unknown model type");
+                        break;
+                }
+                if (ret == null) {
+                    Slog.e(TAG, "Failed to get model state");
+                }
+
+                return ret;
+            }
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3b40164..7f87c4d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2206,24 +2206,25 @@
     }
 
     /**
-     * Set preferred default data.
-     * Set on which slot most cellular data will be on.
-     * It's also usually what we set up internet connection on.
+     * Set which subscription is preferred for cellular data.
+     * It's also usually the subscription we set up internet connection on.
      *
      * PreferredData overwrites user setting of default data subscription. And it's used
-     * by AlternativeNetworkAccessService or carrier apps to switch primary and CBRS
+     * by AlternativeNetworkService or carrier apps to switch primary and CBRS
      * subscription dynamically in multi-SIM devices.
      *
-     * @param slotId which slot is preferred to for cellular data. If it's INVALID, it means
-     *               it's unset and defaultDataSubId is used to determine which modem is preferred.
+     * @param subId which subscription is preferred to for cellular data. If it's
+     *              {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}, it means
+     *              it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *              is used to determine which modem is preferred.
      * @hide
      *
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void setPreferredData(int slotId) {
-        if (VDBG) logd("[setPreferredData]+ slotId:" + slotId);
+    public void setPreferredData(int subId) {
+        if (VDBG) logd("[setPreferredData]+ subId:" + subId);
         setSubscriptionPropertyHelper(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                "setPreferredData", (iSub)-> iSub.setPreferredData(slotId));
+                "setPreferredData", (iSub)-> iSub.setPreferredData(subId));
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 0ccd748..85b4941 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony;
 
-import android.app.PendingIntent;
 import android.telephony.SubscriptionInfo;
 
 interface ISub {
@@ -175,14 +174,14 @@
     int setParentSubId(int parentSubId, int subId);
 
     /**
-     * Set preferred default data.
-     * Set on which slot default data will be on.
+     * Set which subscription is preferred for cellular data. It's
+     * designed to overwrite default data subscription temporarily.
      *
-     * @param slotId which slot is preferred to for cellular data.
+     * @param subId which subscription is preferred to for cellular data.
      * @hide
      *
      */
-    int setPreferredData(int slotId);
+    int setPreferredData(int subId);
 
     /**
      * Get User downloaded Profiles.
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index 5bc8934..571f623 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -22,9 +22,9 @@
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
+import android.graphics.RecordingCanvas;
 import android.os.Bundle;
 import android.os.Trace;
-import android.view.DisplayListCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -88,8 +88,8 @@
             super.onDraw(canvas);
 
             if (canvas.isHardwareAccelerated()) {
-                DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
-                displayListCanvas.drawCircle(mX, mY, mRadius, mPaint);
+                RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+                recordingCanvas.drawCircle(mX, mY, mRadius, mPaint);
             }
         }
 
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
index af8e10b..220016a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
@@ -16,25 +16,13 @@
 
 package com.android.test.hwui;
 
-import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
-import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
-import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
-import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_RARELY;
-
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.GraphicBuffer;
 import android.graphics.Paint;
 import android.graphics.Picture;
-import android.graphics.PixelFormat;
-import android.graphics.SurfaceTexture;
 import android.os.Bundle;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-import android.view.Surface;
-import android.view.ThreadedRenderer;
 import android.widget.ImageView;
 
 public class DrawIntoHwBitmapActivity extends Activity {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
index 7713f5d..e7d7f2b 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
@@ -21,12 +21,12 @@
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.view.DisplayListCanvas;
 import android.view.ThreadedRenderer;
-import android.view.RenderNode;
+import android.graphics.RenderNode;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.AbsoluteLayout;
@@ -206,7 +206,7 @@
                     }
 
                     // Draw frame
-                    DisplayListCanvas canvas = nodeFrame.start(currentFrameBounds.width(),
+                    RecordingCanvas canvas = nodeFrame.start(currentFrameBounds.width(),
                             currentFrameBounds.height());
                     mFrameContent.draw(canvas);
                     nodeFrame.end(canvas);
@@ -228,7 +228,7 @@
                     }
 
                     // Draw Backdrop
-                    DisplayListCanvas canvas = nodeBack.start(currentBackBounds.width(),
+                    RecordingCanvas canvas = nodeBack.start(currentBackBounds.width(),
                             currentBackBounds.height());
                     mBackContent.draw(canvas);
                     nodeBack.end(canvas);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
index be5d7f9..4eb4072 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
@@ -8,9 +8,8 @@
 
 import android.app.Activity;
 import android.util.AttributeSet;
-import android.view.RenderNode;
+import android.graphics.RenderNode;
 import android.view.View;
-import android.widget.LinearLayout;
 
 public class ProjectionActivity extends Activity {
     /**
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
index 2ae960b..9abd7ea 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
@@ -1,13 +1,7 @@
 package com.android.test.hwui;
 
 import android.app.Activity;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
 import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.RenderNode;
 import android.view.View;
 
 public class ProjectionClippingActivity extends Activity {
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index d1f42f8..257043b 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -47,7 +47,8 @@
       fields(that.fields),
       primaryFields(that.primaryFields),
       exclusiveField(that.exclusiveField),
-      uidField(that.uidField) {}
+      uidField(that.uidField),
+      binaryFields(that.binaryFields) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -119,6 +120,9 @@
             } else if (field->message_type()->full_name() ==
                        "android.os.statsd.KeyValuePair") {
               return JAVA_TYPE_KEY_VALUE_PAIR;
+            } else if (field->options().GetExtension(os::statsd::log_mode) ==
+                       os::statsd::LogMode::MODE_BYTES) {
+                return JAVA_TYPE_BYTE_ARRAY;
             } else {
                 return JAVA_TYPE_OBJECT;
             }
@@ -188,6 +192,8 @@
   for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
        it != fields.end(); it++) {
     const FieldDescriptor *field = it->second;
+    bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+                         os::statsd::LogMode::MODE_BYTES;
 
     java_type_t javaType = java_type(field);
 
@@ -197,17 +203,24 @@
       continue;
     } else if (javaType == JAVA_TYPE_OBJECT &&
                atomDecl->code < PULL_ATOM_START_ID) {
-      // Allow attribution chain, but only at position 1.
-      print_error(field,
-                  "Message type not allowed for field in pushed atoms: %s\n",
-                  field->name().c_str());
-      errorCount++;
-      continue;
-    } else if (javaType == JAVA_TYPE_BYTE_ARRAY) {
-      print_error(field, "Raw bytes type not allowed for field: %s\n",
-                  field->name().c_str());
-      errorCount++;
-      continue;
+        // Allow attribution chain, but only at position 1.
+        print_error(field,
+                    "Message type not allowed for field in pushed atoms: %s\n",
+                    field->name().c_str());
+        errorCount++;
+        continue;
+    } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
+        print_error(field, "Raw bytes type not allowed for field: %s\n",
+                    field->name().c_str());
+        errorCount++;
+        continue;
+    }
+
+    if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
+        print_error(field, "Cannot mark field %s as bytes.\n",
+                    field->name().c_str());
+        errorCount++;
+        continue;
     }
   }
 
@@ -233,6 +246,8 @@
        it != fields.end(); it++) {
     const FieldDescriptor *field = it->second;
     java_type_t javaType = java_type(field);
+    bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+                         os::statsd::LogMode::MODE_BYTES;
 
     AtomField atField(field->name(), javaType);
     // Generate signature for pushed atoms
@@ -241,8 +256,10 @@
         // All enums are treated as ints when it comes to function signatures.
         signature->push_back(JAVA_TYPE_INT);
         collate_enums(*field->enum_type(), &atField);
+      } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
+          signature->push_back(JAVA_TYPE_BYTE_ARRAY);
       } else {
-        signature->push_back(javaType);
+          signature->push_back(javaType);
       }
     }
     if (javaType == JAVA_TYPE_ENUM) {
@@ -287,6 +304,10 @@
             errorCount++;
         }
     }
+    // Binary field validity is already checked above.
+    if (isBinaryField) {
+        atomDecl->binaryFields.push_back(it->first);
+    }
   }
 
   return errorCount;
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 31b8b07..450b305 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -89,6 +89,8 @@
 
     int uidField = 0;
 
+    vector<int> binaryFields;
+
     AtomDecl();
     AtomDecl(const AtomDecl& that);
     AtomDecl(int code, const string& name, const string& message);
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 56c8428..1ef34b9 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -66,6 +66,8 @@
             return "double";
         case JAVA_TYPE_STRING:
             return "char const*";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "char const*";
         default:
             return "UNKNOWN";
     }
@@ -88,6 +90,8 @@
             return "double";
         case JAVA_TYPE_STRING:
             return "java.lang.String";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "byte[]";
         default:
             return "UNKNOWN";
     }
@@ -198,13 +202,40 @@
     }
 
     fprintf(out, "    return options;\n");
-    fprintf(out, "  }\n");
+    fprintf(out, "}\n");
 
     fprintf(out,
             "const std::map<int, StateAtomFieldOptions> "
             "AtomsInfo::kStateAtomsFieldOptions = "
             "getStateAtomFieldOptions();\n");
 
+    fprintf(out,
+            "static std::map<int, std::vector<int>> "
+            "getBinaryFieldAtoms() {\n");
+    fprintf(out, "    std::map<int, std::vector<int>> options;\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->binaryFields.size() == 0) {
+            continue;
+        }
+        fprintf(out,
+                "\n    // Adding binary fields for atom "
+                "(%d)%s\n",
+                atom->code, atom->name.c_str());
+
+        for (const auto& field : atom->binaryFields) {
+            fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
+                    make_constant_name(atom->name).c_str(), field);
+        }
+    }
+
+    fprintf(out, "    return options;\n");
+    fprintf(out, "}\n");
+
+    fprintf(out,
+            "const std::map<int, std::vector<int>> "
+            "AtomsInfo::kBytesFieldAtoms = "
+            "getBinaryFieldAtoms();\n");
 
     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
@@ -664,6 +695,9 @@
     fprintf(out,
             "  const static std::map<int, StateAtomFieldOptions> "
             "kStateAtomsFieldOptions;\n");
+    fprintf(out,
+            "  const static std::map<int, std::vector<int>> "
+            "kBytesFieldAtoms;");
     fprintf(out, "};\n");
 
     fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
@@ -698,6 +732,8 @@
             fprintf(out, ", android.os.WorkSource workSource");
         } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
             fprintf(out, ", SparseArray<Object> value_map");
+        } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
+            fprintf(out, ", byte[] %s", field->name.c_str());
         } else {
             fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
         }
@@ -890,6 +926,8 @@
             return "jdouble";
         case JAVA_TYPE_STRING:
             return "jstring";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "jbyteArray";
         default:
             return "UNKNOWN";
     }
@@ -942,6 +980,9 @@
             case JAVA_TYPE_KEY_VALUE_PAIR:
               result += "_KeyValuePairs";
               break;
+            case JAVA_TYPE_BYTE_ARRAY:
+                result += "_bytes";
+                break;
             default:
                 result += "_UNKNOWN";
                 break;
@@ -967,6 +1008,8 @@
             return "D";
         case JAVA_TYPE_STRING:
             return "Ljava/lang/String;";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "[B";
         default:
             return "UNKNOWN";
     }
@@ -1081,6 +1124,25 @@
                 fprintf(out, "    } else {\n");
                 fprintf(out, "        str%d = NULL;\n", argIndex);
                 fprintf(out, "    }\n");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                hadStringOrChain = true;
+                fprintf(out, "    jbyte* jbyte_array%d;\n", argIndex);
+                fprintf(out, "    const char* str%d;\n", argIndex);
+                fprintf(out, "    if (arg%d != NULL) {\n", argIndex);
+                fprintf(out,
+                        "        jbyte_array%d = "
+                        "env->GetByteArrayElements(arg%d, NULL);\n",
+                        argIndex, argIndex);
+                fprintf(out,
+                        "        str%d = "
+                        "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
+                        "d, NULL));\n",
+                        argIndex, argIndex);
+                fprintf(out, "    } else {\n");
+                fprintf(out, "        jbyte_array%d = NULL;\n", argIndex);
+                fprintf(out, "        str%d = NULL;\n", argIndex);
+                fprintf(out, "    }\n");
+
             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 hadStringOrChain = true;
                 for (auto chainField : attributionDecl.fields) {
@@ -1154,7 +1216,10 @@
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
             } else {
-                const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
+                const char* argName = (*arg == JAVA_TYPE_STRING ||
+                                       *arg == JAVA_TYPE_BYTE_ARRAY)
+                                              ? "str"
+                                              : "arg";
                 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
             }
             argIndex++;
@@ -1171,6 +1236,13 @@
                 fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
                         argIndex, argIndex);
                 fprintf(out, "    }\n");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out, "    if (str%d != NULL) { \n", argIndex);
+                fprintf(out,
+                        "        env->ReleaseByteArrayElements(arg%d, "
+                        "jbyte_array%d, 0);\n",
+                        argIndex, argIndex);
+                fprintf(out, "    }\n");
             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_INT) {
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index f635974..3be87d9 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -109,6 +109,28 @@
   oneof event { BadAttributionNodePositionAtom bad = 1; }
 }
 
+message GoodEventWithBinaryFieldAtom {
+    oneof event { GoodBinaryFieldAtom field1 = 1; }
+}
+
+message ComplexField {
+    optional string str = 1;
+}
+
+message GoodBinaryFieldAtom {
+    optional int32 field1 = 1;
+    optional ComplexField bf = 2 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+message BadEventWithBinaryFieldAtom {
+    oneof event { BadBinaryFieldAtom field1 = 1; }
+}
+
+message BadBinaryFieldAtom {
+    optional int32 field1 = 1;
+    optional ComplexField bf = 2;
+}
+
 message BadStateAtoms {
     oneof event {
         BadStateAtom1 bad1 = 1;
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 1936d96..ad3bffac 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -212,5 +212,19 @@
     EXPECT_EQ(0, errorCount);
 }
 
+TEST(CollationTest, PassOnGoodBinaryFieldAtom) {
+    Atoms atoms;
+    int errorCount =
+            collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), &atoms);
+    EXPECT_EQ(0, errorCount);
+}
+
+TEST(CollationTest, FailOnBadBinaryFieldAtom) {
+    Atoms atoms;
+    int errorCount =
+            collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), &atoms);
+    EXPECT_TRUE(errorCount > 0);
+}
+
 }  // namespace stats_log_api_gen
 }  // namespace android
\ No newline at end of file