diff options
382 files changed, 8259 insertions, 4203 deletions
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 eed1db032d9f..c742df3b882b 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 @@ public class CanvasPerfTest { 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 @@ public class CanvasPerfTest { 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 3a4fc7206712..f9c375804599 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.graphics.Outline; 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 a283e0664bc6..d18aa51bfcd3 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 @@ public class RenderNodePerfTest { 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 class RenderNodePerfTest { 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 64f2800ee112..9245c1ba59e4 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 @@ package android.text; 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 @@ public class BoringLayoutCreateDrawPerfTest { 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 ad5a34e44997..a7972f59f382 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 @@ package android.text; 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 @@ public class PaintMeasureDrawPerfTest { 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 d98df059e2d3..00a626750c79 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 1cd0ae13069b..33b1a47413c8 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 deb2b0a74aaa..b40dd6b9dbb7 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 @@ package android.text; 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 @@ public class StaticLayoutCreateDrawPerfTest { 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 e1a38a0956d7..e224fa39422c 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 @@ public class StaticLayoutPerfTest { 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 aa505b533f26..22e516abe926 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 4bbe4049ba35..25cc7078762a 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.AT_MOST; 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 @@ public class TextViewSetTextMeasurePerfTest { 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 dc34b7fe057c..434b8e56dd36 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 @@ public class TextViewPrecomputedTextPerfTest { 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 @@ public class TextViewPrecomputedTextPerfTest { 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 @@ public class TextViewPrecomputedTextPerfTest { 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 @@ public class TextViewPrecomputedTextPerfTest { 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 51df940866d3..870c0209d7c2 100755 --- a/api/current.txt +++ b/api/current.txt @@ -283,7 +283,6 @@ package android { 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 @@ package android { 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 @@ package android.media { 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 @@ package android.media { 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 @@ package android.media { 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 @@ package android.media { 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 @@ package android.media { 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 @@ package android.opengl { 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 @@ package android.provider { 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 @@ package android.view { 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 @@ package android.view { 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 26036ea9c281..7e510827b6ff 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -987,6 +987,7 @@ package android.content { 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 e915cc811676..5dcb392b002d 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -114,7 +114,7 @@ BootAnimation::BootAnimation(sp<Callbacks> callbacks) 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 @@ sp<SurfaceComposerClient> BootAnimation::session() const { 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::threadLoop() 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 parseColor(const char str[7], float color[3]) { 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 @@ void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) 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 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) 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 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) 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 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) 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 @@ bool BootAnimation::preloadZip(Animation& animation) 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 @@ bool BootAnimation::preloadZip(Animation& animation) } } } else { - ALOGE("bootanimation.zip is compressed; must be only stored"); + SLOGE("bootanimation.zip is compressed; must be only stored"); } } } @@ -782,7 +782,7 @@ bool BootAnimation::preloadZip(Animation& animation) 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 @@ bool BootAnimation::playAnimation(const Animation& animation) 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 @@ bool BootAnimation::playAnimation(const Animation& animation) 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 @@ void BootAnimation::releaseAnimation(Animation* animation) const 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 @@ bool BootAnimation::TimeCheckThread::doThreadLoop() { 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 @@ bool BootAnimation::TimeCheckThread::doThreadLoop() { 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 @@ void BootAnimation::TimeCheckThread::addTimeDirWatch() { 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 @@ status_t BootAnimation::TimeCheckThread::readyToRun() { 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 d334f96d47fb..8fa298060d60 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 SkColorType flinger2skia(PixelFormat f) } } -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 sk_sp<SkColorSpace> dataSpaceToColorSpace(android_dataspace d) } } -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 @@ int main(int argc, char** argv) 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 @@ int main(int argc, char** argv) 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 @@ int main(int argc, char** argv) 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 @@ int main(int argc, char** argv) 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 @@ int main(int argc, char** argv) } 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 453bf7e126cd..e33bd8c97a07 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -64,10 +64,22 @@ message StateAtomFieldOption { 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 dfb40a9bd16f..d52dec17952f 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -22,6 +22,7 @@ option java_outer_classname = "AtomsProto"; 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 @@ message Atom { 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 PhoneStateChanged { */ 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 @@ message Notification { 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; + + // Reason for dismissal of a notification. This field is only meaningful for + // TYPE_DISMISS events. + optional int32 dismiss_reason = 12; - // Time since notification was created in milliseconds. - optional int64 since_create_millis = 11; + // The first post time of notification, stable across updates. + optional int64 creation_millis = 13; - // Time since notification was interrupted in milliseconds. - optional int64 since_interruption_millis = 12; + // 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 updated in milliseconds. - optional int64 since_update_millis = 13; + // The most recent update time, or the creation time if no updates. + optional int64 update_millis = 15; - // Time since notification was visible in milliseconds. - optional int64 since_visible_millis = 14; + // The most recent visibility event. + optional int64 visible_millis = 16; } @@ -3102,4 +3092,20 @@ message UserRestrictionChanged { 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 1a9ba8a8de17..ba626f86f913 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -229,6 +229,11 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // 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 805e5833c1eb..2498d9f32d06 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 writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers, // } // // -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 @@ void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size 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 @@ void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size } // 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 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& value 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 ae3e5a1b1dfa..cc4e386bfdf0 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.File; 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 @@ public class TestDrive { 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 @@ public class TestDrive { 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 @@ public class TestDrive { // 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 @@ public class TestDrive { 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 @@ public class TestDrive { + "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 be9ccec7ec86..2d5103875bd1 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -6414,6 +6414,38 @@ HPLandroid/util/proto/EncodedBuffer;->startEditing()V 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/WrappedX509Certificate; 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 1a8a32ec574f..95bcf0ecf132 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -3227,7 +3227,7 @@ android.view.DisplayCutout$ParcelableWrapper$1 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 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 9d3c5c6417af..4756bf40bad3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1425,60 +1425,10 @@ public final class ActivityThread extends ClientTransactionHandler { 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 a30ae799bd3d..3b055665a789 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1283,8 +1283,8 @@ public class AppOpsManager { 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 599c2d2d3594..a2a6b9b4a762 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -36,11 +36,9 @@ import android.database.CrossProcessCursorWrapper; 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.RemoteException; 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 @@ public abstract class ContentResolver { } }); } + + /** {@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 a55dd31f265f..1d0237502812 100644 --- a/core/java/android/content/IContentService.aidl +++ b/core/java/android/content/IContentService.aidl @@ -185,4 +185,6 @@ interface IContentService { 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 c0463e9ae7af..ea1a2fe758af 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1908,6 +1908,22 @@ public class Intent implements Parcelable, Cloneable { @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 7fa2b409c59d..cf019e134bc2 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 final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler { */ 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 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler { } 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 5c4f16a7cf3d..20505ca803dc 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -34,6 +34,7 @@ import dalvik.system.BlockGuard; 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 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen 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 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } } + 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 3ee348ba4865..dbc176614daf 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -24,6 +24,7 @@ import android.os.Message; 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 com.android.internal.annotations.VisibleForTesting; 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 @@ public final class SQLiteConnectionPool implements Closeable { * @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 eb5c720d6309..f9c2c3e2c983 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -22,6 +22,8 @@ import android.annotation.NonNull; 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.Looper; 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 dalvik.system.CloseGuard; 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 @@ public final class SQLiteDatabase extends SQLiteClosable { * @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 @@ public final class SQLiteDatabase extends SQLiteClosable { 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 @@ public final class SQLiteDatabase extends SQLiteClosable { * 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 @@ public final class SQLiteDatabase extends SQLiteClosable { return this; } - /** + /**w * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a> * . * @return @@ -2646,5 +2703,34 @@ public final class SQLiteDatabase extends SQLiteClosable { @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 1c6620467b7c..f220205b5f26 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -189,6 +189,11 @@ public final class SQLiteDebug { * @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 @@ public final class SQLiteDebug { } } - 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 67e5f65d5a1f..ff286fdb42df 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -42,6 +42,9 @@ public final class SQLiteGlobal { /** @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 @@ public final class SQLiteGlobal { 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 5de89e3422ab..56da719e7869 100644 --- a/core/java/android/hardware/location/ContextHubClient.java +++ b/core/java/android/hardware/location/ContextHubClient.java @@ -130,30 +130,42 @@ public class ContextHubClient implements Closeable { * {@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 f94d69b7fa2d..b0b77f31c24d 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -73,7 +73,7 @@ public final class ContextHubManager { * * @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 @@ public final class ContextHubManager { * @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 @@ public final class ContextHubManager { * 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 @@ public final class ContextHubManager { } /** - * 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 d81126a0ac54..7559cd597736 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 @@ interface IContextHubClient { // 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 838765b67dff..e970747d6642 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -20,6 +20,7 @@ import android.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; + import java.lang.ref.WeakReference; /** @@ -131,6 +132,14 @@ public class SoundTriggerModule { @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 @@ public class SoundTriggerModule { } } } - diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 0982d65ee4c9..843db6d28d30 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -41,8 +41,7 @@ import com.android.internal.view.IInputMethodSession; 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 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } switch (msg.what) { - case DO_FINISH_INPUT: - mInputMethodSession.finishInput(); - return; case DO_DISPLAY_COMPLETIONS: mInputMethodSession.displayCompletions((CompletionInfo[])msg.obj); return; @@ -150,11 +146,6 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } @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 f947b5ef9f5b..8b6194c29707 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -28,6 +28,8 @@ import com.android.internal.util.FastPrintWriter; 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 class Binder implements IBinder { 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 8ea061e4a8d0..e0b2c7853eba 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -557,6 +557,7 @@ public final class PowerManager { ServiceType.FORCE_ALL_APPS_STANDBY, ServiceType.OPTIONAL_SENSORS, ServiceType.AOD, + ServiceType.QUICK_DOZE, }) public @interface ServiceType { int NULL = 0; @@ -586,6 +587,11 @@ public final class PowerManager { * 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 0f64c4531bc3..379d28cf10a0 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -1003,11 +1003,38 @@ public class Process { 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 954d18abc6e1..67e52aad9206 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -731,6 +731,8 @@ public final class DocumentsContract { 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 f5660b950c0a..57f33f02ac42 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -46,9 +46,6 @@ import android.util.Log; 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 final class MediaStore { */ 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 @@ public final class MediaStore { } /** - * 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 { - - 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 { + /** + * 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( - 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 ad640219a6a5..80e8f78ec92b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10907,6 +10907,7 @@ public final class Settings { * 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 @@ public final class Settings { * 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 fa7b067deb20..98ed21735e62 100644 --- a/core/java/android/view/GhostView.java +++ b/core/java/android/view/GhostView.java @@ -18,6 +18,8 @@ package android.view; 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 @@ public class GhostView extends View { @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 e48bcfdb7203..9d31bd16b452 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -22,6 +22,8 @@ import android.animation.ValueAnimator; 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 @@ public class RenderNodeAnimator extends Animator { 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 @@ public class RenderNodeAnimator extends Animator { 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 e1ef05941394..d222e0739fa2 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 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; */ 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 6fb1bbabddc2..f3cb3767ec9d 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -22,7 +22,9 @@ import android.content.res.CompatibilityInfo.Translator; 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 @@ public class Surface implements Parcelable { 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 e71182c33c12..67f9399e678a 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -30,6 +30,7 @@ import android.graphics.PixelFormat; 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 35a886fa27a3..d89d634c6a25 100644 --- a/core/java/android/view/TextureLayer.java +++ b/core/java/android/view/TextureLayer.java @@ -31,7 +31,7 @@ import com.android.internal.util.VirtualRefBasePtr; * * @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 997e48fe61ac..0175ba201dd1 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -23,6 +23,7 @@ import android.graphics.Bitmap; 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 @@ public class TextureView extends View { 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 @@ public class TextureView extends View { 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 42690cef9da3..c1ab4d4b895e 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -24,7 +24,9 @@ import android.content.Context; 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 @@ public final class ThreadedRenderer { 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 @@ public final class ThreadedRenderer { * * @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 @@ public final class ThreadedRenderer { * * @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 06b73dd29b3d..6fb32e36fb3f 100644 --- a/core/java/android/view/TouchDelegate.java +++ b/core/java/android/view/TouchDelegate.java @@ -165,7 +165,11 @@ public class TouchDelegate { 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 cc58b8928f6e..1157b287e550 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -57,9 +57,11 @@ import android.graphics.PixelFormat; 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final RenderNode renderNode = mBackgroundRenderNode; if (renderNode != null && renderNode.isValid()) { setBackgroundRenderNodeProperties(renderNode); - ((DisplayListCanvas) canvas).drawRenderNode(renderNode); + ((RecordingCanvas) canvas).drawRenderNode(renderNode); return; } } @@ -20633,7 +20635,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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 58f555dfa305..e0fae21bbdf6 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 8dd03476a2b8..292e933c3f7e 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -23,7 +23,9 @@ import android.content.res.Resources; 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 @@ public class ViewDebug { } 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 e3e2069422fc..a0ab362f3985 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -19,6 +19,7 @@ package android.view; 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 bef8e8fedfdf..170c78367643 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -51,8 +51,10 @@ import android.graphics.PixelFormat; 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 @@ public final class ViewRootImpl implements ViewParent, 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 (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 (changed) { + if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) { // TODO: Don't require regenerating all display lists to apply this setting invalidateWorld(mView); } @@ -3120,7 +3128,7 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, } @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 b2dc1e91bdf7..a99730205136 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 @@ public interface WindowCallbacks { * * @param canvas The canvas to draw on. */ - void onPostDraw(DisplayListCanvas canvas); + void onPostDraw(RecordingCanvas canvas); } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index e370e1175de5..e9acdc321c9d 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -737,45 +737,67 @@ public final class InputMethodManager { return false; } - private static IInputMethodManager getIInputMethodManager() throws ServiceNotFoundException { - if (!isInEditMode()) { - return IInputMethodManager.Stub.asInterface( + @NonNull + private static InputMethodManager createInstance(int displayId, Looper looper) { + return isInEditMode() ? createStubInstance(displayId, looper) + : createRealInstance(displayId, looper); + } + + @NonNull + private static InputMethodManager createRealInstance(int displayId, Looper looper) { + final IInputMethodManager service; + try { + service = IInputMethodManager.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)); + } catch (ServiceNotFoundException e) { + throw new IllegalStateException(e); + } + final InputMethodManager imm = new InputMethodManager(service, displayId, looper); + try { + service.addClient(imm.mClient, imm.mIInputContext, displayId); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); } + return imm; + } + + @NonNull + private static InputMethodManager createStubInstance(int displayId, Looper looper) { // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS. final Class<IInputMethodManager> c = IInputMethodManager.class; - return (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(), - new Class[]{c}, (proxy, method, args) -> { - final Class<?> returnType = method.getReturnType(); - if (returnType == boolean.class) { - return false; - } else if (returnType == int.class) { - return 0; - } else if (returnType == long.class) { - return 0L; - } else if (returnType == short.class) { - return 0; - } else if (returnType == char.class) { - return 0; - } else if (returnType == byte.class) { - return 0; - } else if (returnType == float.class) { - return 0f; - } else if (returnType == double.class) { - return 0.0; - } else { - return null; - } - }); + final IInputMethodManager stubInterface = + (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(), + new Class[]{c}, (proxy, method, args) -> { + final Class<?> returnType = method.getReturnType(); + if (returnType == boolean.class) { + return false; + } else if (returnType == int.class) { + return 0; + } else if (returnType == long.class) { + return 0L; + } else if (returnType == short.class) { + return 0; + } else if (returnType == char.class) { + return 0; + } else if (returnType == byte.class) { + return 0; + } else if (returnType == float.class) { + return 0f; + } else if (returnType == double.class) { + return 0.0; + } else { + return null; + } + }); + return new InputMethodManager(stubInterface, displayId, looper); } - InputMethodManager(int displayId, Looper looper) throws ServiceNotFoundException { - mService = getIInputMethodManager(); + private InputMethodManager(IInputMethodManager service, int displayId, Looper looper) { + mService = service; mMainLooper = looper; mH = new H(looper); mDisplayId = displayId; - mIInputContext = new ControlledInputConnectionWrapper(looper, - mDummyInputConnection, this); + mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this); } /** @@ -785,7 +807,7 @@ public final class InputMethodManager { * @return {@link InputMethodManager} instance * @hide */ - @Nullable + @NonNull public static InputMethodManager forContext(Context context) { final int displayId = context.getDisplayId(); // For better backward compatibility, we always use Looper.getMainLooper() for the default @@ -795,7 +817,7 @@ public final class InputMethodManager { return forContextInternal(displayId, looper); } - @Nullable + @NonNull private static InputMethodManager forContextInternal(int displayId, Looper looper) { final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY; synchronized (sLock) { @@ -803,12 +825,7 @@ public final class InputMethodManager { if (instance != null) { return instance; } - try { - instance = new InputMethodManager(displayId, looper); - instance.mService.addClient(instance.mClient, instance.mIInputContext, displayId); - } catch (ServiceNotFoundException | RemoteException e) { - throw new IllegalStateException(e); - } + instance = createInstance(displayId, looper); // For backward compatibility, store the instance also to sInstance for default display. if (sInstance == null && isDefaultDisplay) { sInstance = instance; diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 3e240cfdb69f..7f1e443f4aa5 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -31,6 +31,7 @@ import android.content.Intent; 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.IndentingPrintWriter; 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 @@ public final class TextClassifierImpl implements TextClassifier { 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 @@ public final class TextClassifierImpl implements TextClassifier { @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 @@ public final class TextClassifierImpl implements TextClassifier { && 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 @@ public final class TextClassifierImpl implements TextClassifier { && 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 @@ public final class TextClassifierImpl implements TextClassifier { 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 @@ public final class TextClassifierImpl implements TextClassifier { ? 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 @@ public final class TextClassifierImpl implements TextClassifier { } } + /** @inheritDoc */ @Override public void onSelectionEvent(SelectionEvent event) { Preconditions.checkNotNull(event); @@ -299,7 +308,29 @@ public final class TextClassifierImpl implements TextClassifier { } } - 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,31 +338,79 @@ public final class TextClassifierImpl implements TextClassifier { 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; } } - private String createId(String text, int start, int end) { + @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) { - return SelectionSessionLogger.createId(text, start, end, mContext, mModel.getVersion(), - mModel.getSupportedLocales()); + 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; } } - @GuardedBy("mLock") // Do not call outside this lock. - private void destroyNativeIfExistsLocked() { - if (mNative != null) { - mNative.close(); - mNative = null; + private String createId(String text, int start, int end) { + synchronized (mLock) { + return SelectionSessionLogger.createId(text, start, end, mContext, mModel.getVersion(), + mModel.getSupportedLocales()); } } @@ -407,20 +486,19 @@ public final class TextClassifierImpl implements TextClassifier { .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 @@ public final class TextClassifierImpl implements TextClassifier { } /** - * 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 @@ public final class TextClassifierImpl implements TextClassifier { /** 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 @@ public final class TextClassifierImpl implements TextClassifier { 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 final class TextClassifierImpl implements TextClassifier { 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 @@ public final class TextClassifierImpl implements TextClassifier { @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 ba665713fb21..6ab7f66aedd3 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -27,11 +27,11 @@ import android.content.Context; 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 @@ public final class WebViewDelegate { * @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 final class WebViewDelegate { */ 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 8027dd7cdb10..48c164f726bc 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -42,8 +42,10 @@ import android.graphics.Paint; 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; 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.LayoutInflater; 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 @@ public class Editor { // 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 @@ public class Editor { 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 16ddd0fc8247..6a3fc0fad4dd 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -33,15 +33,15 @@ import android.graphics.Paint; 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 @@ public final class Magnifier { 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 @@ public final class Magnifier { 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 @@ public final class Magnifier { 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 b8a2dff95c37..c0c689ced521 100644 --- a/core/java/com/android/internal/app/ISoundTriggerService.aidl +++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl @@ -52,4 +52,6 @@ interface ISoundTriggerService { /** 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 8dc97fe86eb3..2b661c25194b 100644 --- a/core/java/com/android/internal/os/LooperStats.java +++ b/core/java/com/android/internal/os/LooperStats.java @@ -49,6 +49,7 @@ public class LooperStats implements Looper.Observer { 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 @@ public class LooperStats implements Looper.Observer { 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 @@ public class LooperStats implements Looper.Observer { 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 a70209c705c0..f14007bd7ac6 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 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame 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 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame 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 469726613513..94140ab7f440 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -16,52 +16,60 @@ 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 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; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.os.Build.VERSION_CODES.M; +import static android.os.Build.VERSION_CODES.N; +import static android.view.View.MeasureSpec.AT_MOST; +import static android.view.View.MeasureSpec.EXACTLY; +import static android.view.View.MeasureSpec.getMode; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.view.Window.DECOR_CAPTION_SHADE_DARK; +import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT; +import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; +import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; +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 java.util.List; +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.DisplayListCanvas; import android.view.Gravity; import android.view.InputQueue; import android.view.KeyEvent; @@ -73,6 +81,7 @@ 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; @@ -81,34 +90,26 @@ 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 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; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static android.os.Build.VERSION_CODES.M; -import static android.os.Build.VERSION_CODES.N; -import static android.view.View.MeasureSpec.AT_MOST; -import static android.view.View.MeasureSpec.EXACTLY; -import static android.view.View.MeasureSpec.getMode; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.Window.DECOR_CAPTION_SHADE_DARK; -import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT; -import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; -import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; -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 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 { @@ -2134,7 +2135,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } @Override - public void onPostDraw(DisplayListCanvas canvas) { + public void onPostDraw(RecordingCanvas canvas) { drawResizingShadowIfNeeded(canvas); } @@ -2152,7 +2153,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind 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 367b713ed78f..794238a3826e 100644 --- a/core/java/com/android/internal/view/IInputMethodSession.aidl +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -29,10 +29,8 @@ import android.view.inputmethod.ExtractedText; * {@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 9263b579ee02..b799728e4a7e 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.Resources; 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 9dbb8d757e15..b417a5629f62 100644 --- a/core/jni/android_hardware_SoundTrigger.cpp +++ b/core/jni/android_hardware_SoundTrigger.cpp @@ -788,6 +788,63 @@ android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz, 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 @@ static const JNINativeMethod gModuleMethods[] = { {"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 da4cdb676283..83a8c2e934c1 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -127,10 +127,9 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) 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 6456fe622f98..bf22dd21516b 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 @@ static void audioCallback(int event, void* user, void *info) { 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_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) { + 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_MORE_DATA: - // a.k.a. tear down - case AudioTrack::EVENT_NEW_IAUDIOTRACK: + case AudioTrack::EVENT_NEW_IAUDIOTRACK: // a.k.a. tear down 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; + 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 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job 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 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job 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 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job 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 4a30babafa49..b52f137da7d6 100644 --- a/core/jni/android_opengl_EGL15.cpp +++ b/core/jni/android_opengl_EGL15.cpp @@ -456,27 +456,41 @@ exit: static jobject android_eglCreatePlatformPixmapSurface (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) { + jniThrowException(_env, "java/lang/UnsupportedOperationException", + "eglCreatePlatformPixmapSurface"); + return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0); +} + +/* EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags ) */ +static jboolean +android_eglWaitSync + (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint flags) { + EGLBoolean _returnValue = (EGLBoolean) 0; + EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); + EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync); + + _returnValue = eglWaitSync( + (EGLDisplay)dpy_native, + (EGLSync)sync_native, + (EGLint)flags + ); + 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; - jarray _array = (jarray) 0; - jint _bufferOffset = (jint) 0; - EGLSurface _returnValue = (EGLSurface) 0; + EGLImage _returnValue = (EGLImage) 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; + EGLContext context_native = (EGLContext) fromEGLHandle(_env, eglcontextGetHandleID, context); EGLAttrib *attrib_list_base = (EGLAttrib *) 0; - jint _attrib_listRemaining; + jint _remaining; 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"; @@ -489,19 +503,16 @@ android_eglCreatePlatformPixmapSurface _exceptionMessage = "offset < 0"; goto exit; } - _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset; + _remaining = _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( + _returnValue = eglCreateImage( (EGLDisplay)dpy_native, - (EGLConfig)config_native, - (void *)native_pixmap, + (EGLContext)context_native, + (EGLenum)target, + (EGLClientBuffer)buffer, (EGLAttrib *)attrib_list ); @@ -510,27 +521,23 @@ exit: _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); + return toEGLHandle(_env, eglimageClass, eglimageConstructor, _returnValue); } -/* EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags ) */ +/* EGLBoolean eglDestroyImage ( EGLDisplay dpy, EGLImage image ) */ static jboolean -android_eglWaitSync - (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint flags) { +android_eglDestroyImage + (JNIEnv *_env, jobject _this, jobject dpy, jobject image) { EGLBoolean _returnValue = (EGLBoolean) 0; EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); - EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync); + EGLImage image_native = (EGLImage) fromEGLHandle(_env, eglimageGetHandleID, image); - _returnValue = eglWaitSync( + _returnValue = eglDestroyImage( (EGLDisplay)dpy_native, - (EGLSync)sync_native, - (EGLint)flags + (EGLImage)image_native ); return (jboolean)_returnValue; } @@ -547,6 +554,8 @@ static const JNINativeMethod methods[] = { {"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 d023d22473c8..ec980800c410 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -904,6 +904,21 @@ static jint android_os_Binder_getThreadStrictModePolicy(JNIEnv* env, jobject cla 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 @@ static const JNINativeMethod gBinderMethods[] = { { "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 62aa1f38ca30..4c7defbf7358 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -51,6 +51,8 @@ using namespace android; 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 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, } env->ReleaseStringUTFChars(file, file8); - char buffer[256]; - const int len = read(fd, buffer, sizeof(buffer)-1); - close(fd); - - if (len < 0) { - if (kDebugProc) { - ALOGW("Unable to open process file: %s fd=%d\n", file8, fd); + 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; } - return JNI_FALSE; } - buffer[len] = 0; + // Resize back down to the amount we read + fileBuffer.resize(numBytesRead); + // Terminate buffer with null byte + fileBuffer.push_back('\0'); + close(fd); - 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 4fdd2bcd4f39..8998cd706dd8 100644 --- a/core/jni/android_view_DisplayListCanvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -183,7 +183,7 @@ static void android_view_DisplayListCanvas_drawCircleProps(jlong canvasPtr, // 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 63b004681df9..bb71a5d4accf 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -576,7 +576,7 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, // JNI Glue // ---------------------------------------------------------------------------- -const char* const kClassPathName = "android/view/RenderNode"; +const char* const kClassPathName = "android/graphics/RenderNode"; static const JNINativeMethod gMethods[] = { // ---------------------------------------------------------------------------- @@ -588,7 +588,7 @@ static const JNINativeMethod gMethods[] = { { "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 @@ static const JNINativeMethod gMethods[] = { }; 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 2e1e130d8375..4eda3abdd0d6 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -166,8 +166,10 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz, } 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 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandl } 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 000000000000..2797550a1ab2 --- /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 1ae5f03a2f04..374c7eab1a2a 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 d41691f4bb1b..62ca7a6fde5b 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 48b59c70a61e..176e89ebc691 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 32cf2e8bac86..a25c9984b1c4 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 fd688a72b7ea..b7908297f60b 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 a7530cea5d73..ad38f3d57c23 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -880,6 +880,9 @@ please see themes_device_defaults.xml. <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 f71df9fb4807..a80725c2758b 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 000000000000..1beb598663d1 --- /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 7360e9f7d6f6..45a501077128 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 @@ public class ForwardDeleteTest { 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 e891fc9d6134..8646c685c998 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 @@ public class TextClassificationManagerTest { } @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 @@ public class TextClassificationManagerTest { } }; } + + 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 44f8737da2c1..28e92dbe264a 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -146,6 +146,7 @@ applications that come with the platform <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 ea0a109c3a04..3db240b54299 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -83,7 +83,7 @@ public abstract class BaseCanvas { // --------------------------------------------------------------------------- // 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 1cd756f9f73f..632edfa4e46a 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -31,8 +31,6 @@ import android.os.StrictMode; 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 @@ public final class Bitmap implements Parcelable { 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 f7acb11c8811..f6d801b3ba43 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 class Picture { 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 index 667fab5537c9..7af006b4bdf0 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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { // 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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { @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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { * 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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { * 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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { * 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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { // 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 @@ public final class DisplayListCanvas extends BaseRecordingCanvas { 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 index 8ae912762fdb..b61488cba934 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 @@ import java.lang.annotation.RetentionPolicy; /** * <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 @@ import java.lang.annotation.RetentionPolicy; * 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 @@ import java.lang.annotation.RetentionPolicy; * 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 @@ import java.lang.annotation.RetentionPolicy; * <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 @@ import java.lang.annotation.RetentionPolicy; * <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 @@ import java.lang.annotation.RetentionPolicy; * * protected void onDraw(Canvas canvas) { * if (canvas.isHardwareAccelerated()) { - * DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas; + * RecordingCanvas displayListCanvas = (RecordingCanvas) canvas; * displayListCanvas.drawDisplayList(mDisplayList); * } * } @@ -143,10 +142,10 @@ public class RenderNode { 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 @@ public class RenderNode { * * @hide */ - interface PositionUpdateListener { + public interface PositionUpdateListener { /** * Called by native by a Rendering Worker thread to update window position @@ -228,7 +227,7 @@ public class RenderNode { * 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 @@ public class RenderNode { * * @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 @@ public class RenderNode { * @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 @@ public class RenderNode { // 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 @@ public class RenderNode { // 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 @@ public class RenderNode { 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 @@ public class RenderNode { 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 @@ public class RenderNode { 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 @@ public class RenderNode { 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 @@ public class RenderNode { * @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 @@ public class RenderNode { * 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 6c1372ff25b4..789e38c4e650 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -39,7 +39,9 @@ import android.graphics.Insets; 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.PathParser; 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 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } /** - * 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 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @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 626bcee9454b..c1f8798faaeb 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 a8dc34af292b..cce9ba31929f 100644 --- a/graphics/java/android/graphics/drawable/RippleForeground.java +++ b/graphics/java/android/graphics/drawable/RippleForeground.java @@ -23,10 +23,10 @@ import android.animation.TimeInterpolator; 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 @@ class RippleForeground extends RippleComponent { } } - 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 @@ class RippleForeground extends RippleComponent { } } - private void drawHardware(DisplayListCanvas c, Paint p) { + private void drawHardware(RecordingCanvas c, Paint p) { startPending(c); pruneHwFinished(); if (mPropPaint != null) { @@ -332,11 +332,11 @@ class RippleForeground extends RippleComponent { * @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 3ca0f8139c02..13d2dae8e281 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -71,15 +71,12 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer 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 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer 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 38204a587402..a02b6af59d5e 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -1068,6 +1068,7 @@ public final class AudioFormat implements Parcelable { 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 e8c97bc0161f..274da11c04ef 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1379,14 +1379,20 @@ public class AudioManager { //==================================================================== // 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 e8fe9fed6bfa..67cc456a7c93 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -21,6 +21,7 @@ import android.annotation.UnsupportedAppUsage; 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 class AudioSystem 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 62e58cab0772..3ec595d9ac11 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -23,7 +23,7 @@ import java.lang.Math; 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.IntDef; 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 @@ public class AudioTrack extends PlayerBase 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 @@ public class AudioTrack extends PlayerBase /** * 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 @@ public class AudioTrack extends PlayerBase * 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 @@ public class AudioTrack extends PlayerBase encoding = format.getEncoding(); } audioParamCheck(rate, channelMask, channelIndexMask, encoding, mode); + mOffloaded = offload; mStreamType = AudioSystem.STREAM_DEFAULT; audioBuffSizeCheck(bufferSizeInBytes); @@ -901,7 +901,6 @@ public class AudioTrack extends PlayerBase } /** - * @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 @@ public class AudioTrack extends PlayerBase .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 @@ public class AudioTrack extends PlayerBase * 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 @@ public class AudioTrack extends PlayerBase * a better solution. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552) public int getLatency() { return native_get_latency(); } @@ -2282,7 +2287,8 @@ public class AudioTrack extends PlayerBase 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 @@ public class AudioTrack extends PlayerBase 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 @@ public class AudioTrack extends PlayerBase 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 @@ public class AudioTrack extends PlayerBase } /** - * @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 @@ public class AudioTrack extends PlayerBase 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 @@ public class AudioTrack extends PlayerBase 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 @@ public class AudioTrack extends PlayerBase } } - //--------------------------------------------------------- // Native methods called from the Java side //-------------------- diff --git a/media/java/android/media/Media2HTTPService.java b/media/java/android/media/Media2HTTPService.java index 957acecab13a..0d46ce404831 100644 --- a/media/java/android/media/Media2HTTPService.java +++ b/media/java/android/media/Media2HTTPService.java @@ -18,9 +18,6 @@ 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; @@ -38,45 +35,8 @@ public class Media2HTTPService { 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 000000000000..066233d95f55 --- /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 71df7dce5ea2..6263e5d65b6e 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -834,10 +834,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { 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 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } @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 9eb0c6d70cfe..cf7bf19909d9 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -365,4 +365,22 @@ public final class SoundTriggerManager { 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 9aae6ad0f080..f855fe2591e1 100644 --- a/opengl/java/android/opengl/EGL15.java +++ b/opengl/java/android/opengl/EGL15.java @@ -146,4 +146,22 @@ public class EGL15 { 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 000000000000..973fef3e666d --- /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 9e99313cd03a..000000000000 --- 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 1072f95371a0..484dbccca9a8 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 62207c5517ec..4e52ff6d016c 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; 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 @@ public class ExternalStorageProvider extends FileSystemProvider { } 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 @@ public class ExternalStorageProvider extends FileSystemProvider { } 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 000000000000..83427d4ebf00 --- /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 000000000000..58b6e86dfc77 --- /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 000000000000..e5fa73f59836 --- /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 000000000000..a88b3e146ea1 --- /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 78963f3e1bfa..027ca094e322 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 class EventLogWriter implements LogWriter { 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 4b9f5727208d..379a820da167 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 @@ public interface LogWriter { * 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 1e5b378e931c..662fa106e3f0 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 @@ public class MetricsFeatureProvider { } } - /** - * 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 class MetricsFeatureProvider { } } - 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 @@ public class MetricsFeatureProvider { 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 f4fd77930506..7a7f0d4a0fd0 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 com.android.settingslib.SettingsLibRobolectricTestRunner; 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 @@ import java.util.List; @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 @@ public class MetricsFeatureProviderTest { mProvider.logDashboardStartIntent(mContext, null /* intent */, MetricsEvent.SETTINGS_GESTURES); - verifyNoMoreInteractions(mockLogWriter); + verifyNoMoreInteractions(mLogWriter); } @Test @@ -86,7 +71,7 @@ public class MetricsFeatureProviderTest { 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 @@ public class MetricsFeatureProviderTest { 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 b58ea00997ef..f4922088bb05 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 @@ public interface ActivityStarter { 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 000000000000..21c9051157d1 --- /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 000000000000..51c442abf2fd --- /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 41dd0b36d160..9c41fca7d224 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 a795442c62f9..7d8a1f5bbbc7 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 33f7e750c390..bfb5bf9c0499 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 4b385fc3d6e1..9f3ae3a8be45 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 dfa4bf922c8f..00f8f869008e 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 4ae2d4181656..32a7147cba85 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 99840619642d..110680751347 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 c2759da5e66b..d4122525c70b 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 787f91e026bf..555f443ff38e 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 b90b4dd3a585..04623478804c 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 3077433ee40e..395de193b35a 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 c0c095212908..fcad97bdb75f 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 f7d51844482a..1b55d390063f 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 895faf8d7b2d..65c5fb55e81a 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 461a328e7878..07476aa1930a 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 ade59ab6fbaa..db3834b54f35 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 bea5c3f3c10c..7b19b3697351 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 c321593106a0..74b1c4489bf3 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 138f2b027c2b..5223a9928b7f 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 88115a5c4e24..ca09219ad593 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 27f043a684f1..7b4fdaddb450 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 7825adeb5aa8..f8f79cea36ee 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 7ddcb5a98cf2..789436170afc 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 cd209717c687..47aaaedf1b52 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 0a35aec1019a..ea16ba4b31ef 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 7fe3d9ddb47a..b7da3835e6dd 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 379e112fe31a..19e9b6400f20 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 7fe3d9ddb47a..b7da3835e6dd 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 7fe3d9ddb47a..b7da3835e6dd 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 5be13ea0c6f2..97ddf61bab35 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 52b311bbaf9c..35499f0173d7 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 0329430fecc3..54364a5f6210 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 80313e79a54f..90e9334eb47c 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 9e19723e6daf..c6314e4a7315 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 7ef324f00b1b..ca38030cf79c 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 dd82e087f4f1..412bee1d6036 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 f9a916545f19..8821178de4bc 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 297f8f442bc4..e37722a00c3e 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 bea5481d11af..80f3c93cd725 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 fd2c102c590a..cf5692b274cf 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 bf77c0dc2799..ac34e9a11c70 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 cf54bef24087..5df6999c7867 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 534cabd51b66..f09a8b30a8d9 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 3b4e7730ce86..8973ecf0022a 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 ef5f2dc4d1f8..2e3040c523f6 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 7119cb164d7e..fd15fc3d95b1 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 99f413dca828..37fabb856729 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 ad2003d5cb8c..0d60e6ca8fb9 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 81870e563320..c651f9eabdda 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 7e71fbe0c6b6..f91ffb054403 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 89c7ff89c23c..b79ea7b18e79 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 4d0c97cb8b9e..0731a5e616b8 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 45f694438693..c4c642f01a9c 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 dfa2bb472232..90148806a142 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 fc8a7d262186..51cb1b1aaff5 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 1b8adccd37b3..d442258ad8cb 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 2dccd89c53bb..e26df8b29c4c 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 7c906ca60063..6f5e230a3efd 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 a5ffd0f699ce..d13193b7effa 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 5abde4e55d57..a5cad4e0c6b6 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 878e40474485..978fc0e8df68 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 5a8e02249059..103ca46fe1a0 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 aac2d5ee84e8..8ed1558e10a9 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 e6f7abb4b266..7a6a1e3051b3 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 1103b3cc7f5b..62970aa3c7cb 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 5db7a3cdb391..81ff8e2ae967 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 e77c5cd81f8f..4f2845ee43ae 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 58d794941bbd..60ca5322976c 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 9f4cedf780f8..a78f5cd4e552 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 5a1fff4e46f2..7e9a9163c2a8 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 41bac3880551..22ef98c6b06a 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 4c0df1346209..f26d1babed99 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 81be3f6ecfb7..e6ed4dc6636b 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 4c0df1346209..f26d1babed99 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 b5bd02d55330..c553f6e480fe 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 23324a212978..07aa66aadd7f 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 98b79be6dc16..aac62a25e5a9 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 d871cb4eaba3..58e176a9ba8d 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 e8f04affe344..1323fcd3ccf1 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 429e84d6ba24..8f0866536946 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 a1648765ed88..609f332622f0 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 37614d99a0d2..72ae99b0ebfc 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 5cbd2db31c94..a73d0e7dd5b1 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 1f498e653c35..02457d94cbad 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 6c8f728d386f..a6d769937fa9 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 d72d2d6976ef..8c786874dad3 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 c67aca487553..21cf1f2637eb 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 edb9262ca277..fb200ecf120c 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 3d825204342e..82b56a2fd4c2 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 6b9c73746897..b02ceae289e0 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 e2b5df4de7a1..a128e7ff21fc 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 8f9855763275..c7b9178a3f83 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 27cad95967dd..0bfcdcfdfedd 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 da768b6350f5..cf93802ba8a4 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 116f98b2b842..c5a2f9091c9a 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 53d3b9cd3da1..2fc207a5e699 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 19e8673fba89..114d69e35e39 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 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; /** * 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 898d64a1ea1a..7e0f8fe2e033 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 @@ import java.util.List; /** * 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 852463ffc188..f02bc5ab15e1 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 @@ import java.util.ArrayList; /** * 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 f69e91145dfc..8b3ae42ef479 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 @@ import java.util.List; * 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 996c837ba121..b50aa76e1d0d 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 @@ import java.util.Map; /** * 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 b51004bf6d56..368e50362cd6 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.ArrayList; 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 @@ public class Task { 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 @@ public class Task { /** * 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 class Task { 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 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public int colorBackground; @ViewDebug.ExportedProperty(category="recents") + @Deprecated public boolean useLightOnPrimaryColor; /** @@ -153,10 +173,13 @@ public class Task { * 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 @@ public class Task { * Resize mode. See {@link ActivityInfo#resizeMode}. */ @ViewDebug.ExportedProperty(category="recents") + @Deprecated public int resizeMode; @ViewDebug.ExportedProperty(category="recents") @@ -173,12 +197,31 @@ public class Task { @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 @@ public class Task { /** * 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 @@ public class Task { /** * Add a callback. */ + @Deprecated public void addCallback(TaskCallbacks cb) { if (!mCallbacks.contains(cb)) { mCallbacks.add(cb); @@ -237,11 +282,13 @@ public class Task { /** * 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 @@ public class Task { } /** 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 @@ public class Task { } /** 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 5f3dcd16e074..d378189b1675 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 @@ import android.util.SparseArray; /** * 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 23582d4bc21d..342cb75b2c14 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 @@ public abstract class TaskKeyCache<V> { * 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 @@ public abstract class TaskKeyCache<V> { * 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 @@ public abstract class TaskKeyCache<V> { } /** 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 @@ public abstract class TaskKeyCache<V> { /** 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 fbb6acebc8e0..6b9b9f55e49e 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 @@ import java.util.concurrent.ConcurrentLinkedQueue; /** * 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 c731ac9b8886..fd92bca7fcda 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 @@ import java.util.List; /** * 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 2de7f74ba477..26f6b596e023 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 @@ import java.util.List; * 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 45728c403ac4..30bea32dedff 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 @@ import com.android.systemui.shared.recents.utilities.Utilities; /** * 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 000000000000..c42e7e3fd216 --- /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 000000000000..a5299038d3a9 --- /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 000000000000..eaf8d9b57398 --- /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 b2b140e4b0a9..de2a3e44841e 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 @@ package com.android.systemui.shared.system; 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 @@ public class WindowCallbacksCompat { } @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 265a961cd985..34df15f17869 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.telephony.TelephonyManager; 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 @@ import java.io.File; */ 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/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java index a3862eb72362..a543d1712299 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -102,7 +102,8 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { findViewById(R.id.key9) }, new View[]{ - null, findViewById(R.id.key0), findViewById(R.id.key_enter) + findViewById(R.id.delete_button), findViewById(R.id.key0), + findViewById(R.id.key_enter) }, new View[]{ null, mEcaView, null diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 6d1313c15106..db786677f0b3 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.Handler; 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.GridLayout; 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 @@ public class KeyguardStatusView extends GridLayout implements private TextView mLogoutView; private KeyguardClockSwitch mClockView; - private View mClockSeparator; private TextView mOwnerInfo; private KeyguardSliceView mKeyguardSlice; private Runnable mPendingMarqueeStart; @@ -75,8 +75,8 @@ public class KeyguardStatusView extends GridLayout implements 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 @@ public class KeyguardStatusView extends GridLayout implements } 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 @@ public class KeyguardStatusView extends GridLayout implements } /** - * 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 @@ public class KeyguardStatusView extends GridLayout implements 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 @@ public class KeyguardStatusView extends GridLayout implements @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 @@ public class KeyguardStatusView extends GridLayout implements } } mOwnerInfo.setText(info); + updateDark(); } @Override @@ -434,7 +407,6 @@ public class KeyguardStatusView extends GridLayout implements 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 45f1686e0c9e..08691ec10d6a 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -54,7 +54,7 @@ public class NumPadKey extends ViewGroup { if (mTextView != null && mTextView.isEnabled()) { mTextView.append(Character.forDigit(mDigit, 10)); } - userActivity();; + userActivity(); } }; @@ -118,7 +118,7 @@ public class NumPadKey extends ViewGroup { 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 e58538db9cea..e1b8dc839bde 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -29,46 +29,69 @@ public class ActivityStarterDelegate implements ActivityStarter { @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 2c821b25f0a5..494880e96ff7 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.EnhancedEstimates; 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 @@ public class Dependency extends SystemUI { 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 77f4bf529f21..d8eb96504e79 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.service.wallpaper.WallpaperService; 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 @@ public class ImageWallpaper extends WallpaperService { 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 000000000000..52ba66a93524 --- /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 3007b6e68b78..c84449683c1c 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -207,11 +207,11 @@ public class ScreenDecorations extends SystemUI implements Tunable { 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 78053b28c4c3..92aa652131ba 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -194,6 +194,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv 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 258b6f61d4c0..c4bf27b5104a 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.keyguard.DismissCallbackRegistry; 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 @@ public class SystemUIFactory { 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 38a90cfd96a5..53cdee549536 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 @@ public class AssistManager implements ConfigurationChangedReceiver { // 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 5739c997d8bf..96af08b6bf6b 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 @@ public class CarNotificationEntryManager extends NotificationEntryManager { // 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 000000000000..f34d6b3e03e7 --- /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 a015a18cd9a8..e4b2e07dc81e 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.internal.widget.LockPatternUtils; 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 @@ public class CarSystemUIFactory extends SystemUIFactory { () -> 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 f217596bd4a9..5bb5b2da32b4 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.util.SparseArray; 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 5c0b3289c61a..daaefb9b2559 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.Handler; 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 @@ public class CommandQueue extends IStatusBar.Stub { 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 @@ public class CommandQueue extends IStatusBar.Stub { } @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 class CommandQueue extends IStatusBar.Stub { } } - 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 @@ public class CommandQueue extends IStatusBar.Stub { 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 18151d0e794a..1f576342d5cd 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.CanvasProperty; 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 @@ public class KeyguardAffordanceView extends ImageView { // 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 cfa09bc93adb..f3a46ce5778a 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 android.util.Log; 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { // 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { // 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { 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 89a842e11c68..bc662e3d8855 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 java.io.FileDescriptor; -import java.io.PrintWriter; +import com.android.systemui.statusbar.notification.NotificationData.Entry; -/** - * 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); - } - - /** - * 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; - } - - 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()); - } + void setUpWithPresenter(NotificationPresenter presenter); - private void setShowLockscreenNotifications(boolean show) { - mShowLockscreenNotifications = show; - } + int getCurrentUserId(); - private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) { - mAllowLockscreenRemoteInput = allowLockscreenRemoteInput; - } + boolean isCurrentProfile(int userId); - 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 destroy(); - setShowLockscreenNotifications(show && allowedByDpm); + SparseArray<UserInfo> getCurrentProfiles(); - 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; + void setLockscreenPublicMode(boolean isProfilePublic, int userId); - 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); - } + boolean shouldShowLockscreenNotifications(); - public boolean isLockscreenPublicMode(int userId) { - if (userId == UserHandle.USER_ALL) { - return mLockscreenPublicMode.get(mCurrentUserId, false); - } - return mLockscreenPublicMode.get(userId, false); - } + boolean shouldHideNotifications(int userId); + boolean shouldHideNotifications(String key); + boolean shouldShowOnKeyguard(StatusBarNotification sbn); - /** - * 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; - } + boolean isAnyProfilePublicMode(); - public SparseArray<UserInfo> getCurrentProfiles() { - return mCurrentProfiles; - } + void updatePublicMode(); - public void destroy() { - mContext.unregisterReceiver(mBaseBroadcastReceiver); - mContext.unregisterReceiver(mAllUsersReceiver); - } + boolean needsRedaction(Entry entry); - @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 000000000000..178c5c516e7b --- /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 2db99453e36c..c437b14e015c 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 @@ public class NotificationMediaManager implements Dumpable { 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 @@ public class NotificationMediaManager implements Dumpable { } }; + @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 @@ public class NotificationMediaManager implements Dumpable { // 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 class NotificationMediaManager implements Dumpable { 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 @@ public class NotificationMediaManager implements Dumpable { } if (metaDataChanged) { - mEntryManager.updateNotifications(); + getEntryManager().updateNotifications(); } mPresenter.updateMediaMetaData(metaDataChanged, true); } @@ -272,4 +351,204 @@ public class NotificationMediaManager implements Dumpable { } 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 c58eb80efd25..5c8f4cbf6078 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.content.Intent; 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 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow * 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 @@ public interface NotificationPresenter extends NotificationData.Environment, 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 @@ public interface NotificationPresenter extends NotificationData.Environment, 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 ea7e03e686b5..f30377ead957 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 static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT 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.IStatusBarService; 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 @@ public class NotificationRemoteInputManager implements Dumpable { 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 @@ public class NotificationRemoteInputManager implements Dumpable { @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 @@ public class NotificationRemoteInputManager implements Dumpable { return true; } if (mUserManager.getUserInfo(userId).isManagedProfile() - && mPresenter.isDeviceLocked(userId)) { + && mKeyguardManager.isDeviceLocked(userId)) { mCallback.onLockedWorkRemoteInput(userId, row, view); return true; } @@ -291,20 +299,26 @@ public class NotificationRemoteInputManager implements Dumpable { } }; + 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 @@ public class NotificationRemoteInputManager implements Dumpable { // 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 1495abf9310c..cd3da123ed32 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.ViewTreeObserver; 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 @@ public class NotificationShelf extends ActivatableNotificationView implements } @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 5b3082b04d58..92765bbec5b1 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.View; 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.VisualStabilityManager; 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 @@ public class NotificationViewHierarchyManager { 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 @@ public class NotificationViewHierarchyManager { 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 class NotificationViewHierarchyManager { } public void setUpWithPresenter(NotificationPresenter presenter, - NotificationEntryManager entryManager, NotificationListContainer listContainer) { + NotificationListContainer listContainer) { mPresenter = presenter; - mEntryManager = entryManager; mListContainer = listContainer; } @@ -291,9 +305,9 @@ public class NotificationViewHierarchyManager { 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 @@ public class NotificationViewHierarchyManager { 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 @@ public class NotificationViewHierarchyManager { && !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 @@ public class NotificationViewHierarchyManager { } 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 cc5fbe53bba4..1e04377e25b2 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.graphics.drawable.Icon; 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.ViewDebug; 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 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi 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 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi 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 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi 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 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi 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 78a5817c32b2..12c0fcbed204 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 @@ public class StatusBarStateController { 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 class StatusBarStateController { } } + 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 24665eac76a7..879934146ac0 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 @@ public class CarStatusBar extends StatusBar implements } @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 8cae80635e69..9e99fbb3afc0 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 @@ public class AppOpsListener implements AppOpsManager.OnOpActiveChangedListener { // 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 @@ public class AppOpsListener implements AppOpsManager.OnOpActiveChangedListener { 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 @@ public class AppOpsListener implements AppOpsManager.OnOpActiveChangedListener { @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 fbf12ed39561..3539fff8bb33 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.util.ArraySet; 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.Comparator; 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 @@ public class NotificationData { 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 @@ public class NotificationData { 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 class NotificationData { } }; - 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 @@ public class NotificationData { 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 class NotificationData { */ 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 @@ public class NotificationData { 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 @@ public class NotificationData { /** * 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 28d339aaeab2..3bea7db14313 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.Dependency; 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.NotificationPresenter; 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. = new ArrayList<>(); private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; - private final class NotificationClicker implements View.OnClickListener { @Override @@ -159,7 +156,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return mNotificationData; } + protected Context getContext() { + return mContext; + } + + protected NotificationPresenter getPresenter() { + return mPresenter; + } + public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() { return mGutsManager::openGuts; } @@ -348,7 +388,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. // 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. extender.setShouldManageLifetime(entry, false /* shouldManage */); } - mMediaManager.onNotificationRemoved(key); + getMediaManager().onNotificationRemoved(key); mForegroundServiceController.removeNotification(entry.notification); if (entry.row != null) { @@ -602,8 +642,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. 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 e96e176cc503..b5fbde136c87 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 @@ public class NotificationLogger { 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 @@ public class NotificationLogger { 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 8110c1c98dec..22c37fdb11cc 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 @@ package com.android.systemui.statusbar.notification.row; 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.ColorDrawable; 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.Interpolators; 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT, freeViewRunnable); break; + case FLAG_CONTENT_VIEW_PUBLIC: + getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED, + freeViewRunnable); default: break; } @@ -557,6 +564,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mIconAnimationRunning) { setIconAnimationRunning(true); } + if (mLastChronometerRunning) { + setChronometerRunning(true); + } if (mNotificationParent != null) { mNotificationParent.updateChildrenHeaderAppearance(); } @@ -615,7 +625,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } 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 class ExpandableNotificationRow extends ActivatableNotificationView } 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 78564515a2c2..11cf8e046200 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 class NotificationContentView extends FrameLayout { } 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 @@ public class NotificationContentView extends FrameLayout { } 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 class NotificationContentView extends FrameLayout { } 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 class NotificationContentView extends FrameLayout { } 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 f4ef0f865a76..24999525ab72 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.Intent; 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 android.view.accessibility.AccessibilityManager; 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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // 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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx 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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx 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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mCheckSaveListener, onSettingsClick, onAppSettingsClick, - mPresenter.isDeviceProvisioned(), + mDeviceProvisionedController.isDeviceProvisioned(), row.getIsNonblockable(), isForBlockingHelper, row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE); @@ -317,6 +333,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx 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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx guts.setVisibility(View.VISIBLE); final boolean needsFalsingProtection = - (mPresenter.isPresenterLocked() && + (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !mAccessibilityManager.isTouchExplorationEnabled()); guts.openControls( @@ -442,6 +462,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } 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 ea1892be1b1f..38d6b3593be2 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.internal.annotations.VisibleForTesting; 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 class NotificationInflater { 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 @@ public class NotificationInflater { 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 @@ public class NotificationInflater { 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 @@ public class NotificationInflater { } /** + * 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 @@ public class NotificationInflater { 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 @@ public class NotificationInflater { 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 659f6c75c703..30d17017ca1c 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.ObjectAnimator; 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.Bundle; 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.NotificationMenuRowPlugin.OnMenuEv 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.EmptyShadeView; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.StatusBarState; 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.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.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; 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.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.StatusBarStateController; -import com.android.systemui.statusbar.notification.FakeShadowView; -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.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.NotificationGroupManager.OnGroupChan 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd // 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private void setStatusBarState(int statusBarState) { + @VisibleForTesting + protected void setStatusBarState(int statusBarState) { mStatusBarState = statusBarState; mAmbientState.setStatusBarState(statusBarState); } @@ -4942,7 +4931,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return; } - mStatusBar.addPostCollapseAction(() -> { + mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); for (ExpandableNotificationRow rowToRemove : viewsToRemove) { if (canChildBeDismissed(rowToRemove)) { @@ -5042,6 +5031,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd 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 c094669e67bf..8325bf8085bd 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.Dependency; 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 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { */ 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 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { 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 587b40d926d2..4eca6bb4c3e7 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 @@ public class ButtonDispatcher { } } } + + /** + * 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 a781be69c93e..fa63831b5e1b 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @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 c7ab27ba715d..5dded527a7fb 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 @@ package com.android.systemui.statusbar.phone; 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 @@ import com.android.systemui.statusbar.policy.KeyButtonView; */ public class ContextualButton extends ButtonDispatcher { + private ContextButtonListener mListener; + private ContextualButtonGroup mGroup; + protected final @DrawableRes int mIconResId; /** @@ -64,6 +69,48 @@ public class ContextualButton extends ButtonDispatcher { 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 @@ public class ContextualButton extends ButtonDispatcher { 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 1b039663ab73..970304399b67 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 @@ public class ContextualButtonGroup extends ButtonDispatcher { * @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 072343a8b101..543949768f05 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.view.accessibility.AccessibilityNodeInfo; 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 class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } }; + public void initFrom(KeyguardBottomAreaView oldBottomArea) { + setKeyguardIndicationController(oldBottomArea.mIndicationController); + setStatusBar(oldBottomArea.mStatusBar); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -578,7 +584,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - private void launchVoiceAssist() { + @VisibleForTesting + void launchVoiceAssist() { Runnable runnable = new Runnable() { @Override public void run() { @@ -787,6 +794,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL 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 8ac867727e65..235629bbb509 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 836a55fde0f1..4a7bc3a24353 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 @@ public class KeyguardClockPositionAlgorithm { 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 76ddca47d33e..6111178bbac9 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 d67669289915..462201c6dac2 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 @@ package com.android.systemui.statusbar.phone; 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 000000000000..b3423a84542e --- /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 40ddf5b497ae..673cdb7c78ac 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.app.WallpaperColors; 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 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen 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 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen 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 80f35060b737..59c15f15e4f7 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.NAVIGATION_HINT_IME_SHOWN; 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.Binder; 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.View; 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; 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.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyButtonView; -import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.notification.stack.StackStateAnimator; 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 class NavigationBarFragment extends Fragment implements Callbacks { 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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private int mNavigationIconHints = 0; private int mNavigationBarMode; - private boolean mAccessibilityFeedbackEnabled; private AccessibilityManager mAccessibilityManager; private MagnificationContentObserver mMagnificationObserver; private ContentResolver mContentResolver; @@ -158,18 +145,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { 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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { @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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } }; + 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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } 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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { 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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { 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 @@ public class NavigationBarFragment extends Fragment implements Callbacks { 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,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { 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; + if (mNavigationBarView != null) { + mNavigationBarView.getRotateSuggestionButton().onDisable2FlagChanged(state2); + } } // ----- Internal stuffz ----- @@ -725,7 +492,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } private boolean shouldDisableNavbarGestures() { - return !mStatusBar.isDeviceProvisioned() + return !mDeviceProvisionedController.isDeviceProvisioned() || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0; } @@ -778,9 +545,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick); updateAccessibilityServicesState(mAccessibilityManager); - ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton(); - rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick); - rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover); updateScreenPinningGestures(); } @@ -1000,27 +764,14 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } } - 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 +817,10 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } } - 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 +839,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } }; - 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 e92656ae0c02..2ab5958a12d2 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.PropertyValuesHolder; 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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav 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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav @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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav 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 class NavigationBarView extends FrameLayout implements PluginListener<Nav } public void onNavigationButtonLongPress(View v) { - mGestureHelper.onNavigationButtonLongPress(v); + if (mGestureHelper != null) { + mGestureHelper.onNavigationButtonLongPress(v); + } } public void onPanelExpandedChange(boolean expanded) { @@ -744,27 +746,12 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav 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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav @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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav 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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav 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 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav 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 b19f57d0dc93..21b98db11a36 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 @@ public class NotificationIconAreaController implements DarkReceiver { private ViewGroup mNotificationScrollLayout; private Context mContext; private boolean mFullyDark; - private boolean mHasShelfIconsWhenFullyDark; public NotificationIconAreaController(Context context, StatusBar statusBar) { mStatusBar = statusBar; @@ -176,33 +175,10 @@ public class NotificationIconAreaController implements DarkReceiver { 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 e31bad65dbb2..31facb79045e 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; 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 @@ public class NotificationPanelView extends PanelView implements 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 @@ public class NotificationPanelView extends PanelView implements 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 @@ public class NotificationPanelView extends PanelView implements // 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 @@ public class NotificationPanelView extends PanelView implements if (suppressedSummary) { continue; } - if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard( + if (!mLockscreenUserManager.shouldShowOnKeyguard( row.getStatusBarNotification())) { continue; } @@ -2414,7 +2425,7 @@ public class NotificationPanelView extends PanelView implements return true; case StatusBarState.SHADE_LOCKED: if (!mQsExpanded) { - mStatusBar.goToKeyguard(); + mShadeController.goToKeyguard(); } return true; case StatusBarState.SHADE: @@ -2617,7 +2628,7 @@ public class NotificationPanelView extends PanelView implements } if (showIconsWhenExpanded != mShowIconsWhenExpanded) { mShowIconsWhenExpanded = showIconsWhenExpanded; - mStatusBar.recomputeDisableFlags(false); + mCommandQueue.recomputeDisableFlags(false); } } @@ -2904,7 +2915,7 @@ public class NotificationPanelView extends PanelView implements if (hideIcons != mHideIconsDuringNotificationLaunch) { mHideIconsDuringNotificationLaunch = hideIcons; if (!hideIcons) { - mStatusBar.recomputeDisableFlags(true /* animate */); + mCommandQueue.recomputeDisableFlags(true /* animate */); } } } @@ -2972,6 +2983,7 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.updateSpeedBumpIndex(); mNotificationStackScroller.updateFooter(); updateShowEmptyShadeView(); + mNotificationStackScroller.updateIconAreaViews(); } public void onUpdateRowStates() { @@ -3019,6 +3031,10 @@ public class NotificationPanelView extends PanelView implements 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/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 57c243957b48..f29b7cab5cbc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -227,6 +227,16 @@ public abstract class PanelView extends FrameLayout { mUnlockFalsingThreshold = res.getDimensionPixelSize(R.dimen.unlock_falsing_threshold); } + private void addMovement(MotionEvent event) { + // Add movement to velocity tracker using raw screen X and Y coordinates instead + // of window coordinates because the window frame may be moving at the same time. + float deltaX = event.getRawX() - event.getX(); + float deltaY = event.getRawY() - event.getY(); + event.offsetLocation(deltaX, deltaY); + mVelocityTracker.addMovement(event); + event.offsetLocation(-deltaX, -deltaY); + } + public void setTouchAndAnimationDisabled(boolean disabled) { mTouchDisabled = disabled; if (mTouchDisabled) { @@ -307,7 +317,7 @@ public abstract class PanelView extends FrameLayout { mTouchAboveFalsingThreshold = false; mCollapsedAndHeadsUpOnDown = isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp(); - mVelocityTracker.addMovement(event); + addMovement(event); if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) || mPeekAnimator != null) { mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning) @@ -341,7 +351,7 @@ public abstract class PanelView extends FrameLayout { } break; case MotionEvent.ACTION_MOVE: - mVelocityTracker.addMovement(event); + addMovement(event); float h = y - mInitialTouchY; // If the panel was collapsed when touching, we only need to check for the @@ -386,7 +396,7 @@ public abstract class PanelView extends FrameLayout { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - mVelocityTracker.addMovement(event); + addMovement(event); endMotionEvent(event, x, y, false /* forceCancel */); break; } @@ -573,7 +583,7 @@ public abstract class PanelView extends FrameLayout { mHasLayoutedSinceDown = false; mUpdateFlingOnLayout = false; mTouchAboveFalsingThreshold = false; - mVelocityTracker.addMovement(event); + addMovement(event); break; case MotionEvent.ACTION_POINTER_UP: final int upPointer = event.getPointerId(event.getActionIndex()); @@ -593,7 +603,7 @@ public abstract class PanelView extends FrameLayout { break; case MotionEvent.ACTION_MOVE: final float h = y - mInitialTouchY; - mVelocityTracker.addMovement(event); + addMovement(event); if (scrolledToBottom || mTouchStartedInEmptyArea || mAnimatingOnDown) { float hAbs = Math.abs(h); if ((h < -mTouchSlop || (mAnimatingOnDown && hAbs > mTouchSlop)) 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 59863ecb1191..2129835945d7 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 @@ package com.android.systemui.statusbar.phone; 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 android.widget.LinearLayout; 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 @@ public class PhoneStatusBarView extends PanelBar { 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 @@ public class PhoneStatusBarView extends PanelBar { super(context, attrs); mBarTransitions = new PhoneStatusBarTransitions(this); + mCommandQueue = getComponent(context, CommandQueue.class); } public BarTransitions getBarTransitions() { @@ -166,7 +170,7 @@ public class PhoneStatusBarView extends PanelBar { @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 15e189cc8baf..855592fb9bb9 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; + 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 RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId, - @StyleRes int style) { + @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 setStyle(@StyleRes int styleRes) { - mStyleRes = styleRes; + 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 @@ public class RotationContextButton extends ContextualButton { 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 000000000000..e546119968aa --- /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 56e5a1e1bd6f..b9ca94956dc9 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 android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT 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.Notification; 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.ComponentName; 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.provider.Settings; 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.RemoteAnimationAdapter; 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.accessibility.AccessibilityManager; 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.DemoMode; 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.recents.ScreenPinningRequest; 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; 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 @@ import java.util.Map; 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 @@ public class StatusBar extends SystemUI implements DemoMode, /** 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 @@ public class StatusBar extends SystemUI implements DemoMode, // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window - private TextView mNotificationPanelDebugText; // settings private QSPanel mQSPanel; @@ -385,15 +357,12 @@ public class StatusBar extends SystemUI implements DemoMode, // 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 @@ public class StatusBar extends SystemUI implements DemoMode, private int mInteractingWindows; private boolean mAutohideSuspended; private int mStatusBarMode; - private int mMaxKeyguardNotifications; private ViewMediatorCallback mKeyguardViewMediatorCallback; protected ScrimController mScrimController; @@ -479,9 +447,6 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, )); } - 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, // 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 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow); mHeadsUpAppearanceController.readFrom(oldController); mStatusBarWindow.setStatusBarView(mStatusBarView); - setAreThereNotifications(); + updateAreThereNotifications(); checkBarModes(); }).getFragmentManager() .beginTransaction() @@ -872,13 +806,6 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, // 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); + mMediaManager.setBiometricUnlockController(mBiometricUnlockController); Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked); Trace.endSection(); } @@ -1234,73 +1195,13 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, .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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - /** - * 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - protected void setHeadsUpUser(int newUserId) { - if (mHeadsUpManager != null) { - mHeadsUpManager.setUser(newUserId); - } - } - public boolean isKeyguardCurrentlySecure() { return !mUnlockMethodCache.canSkipBouncer(); } @@ -1868,6 +1523,11 @@ public class StatusBar extends SystemUI implements DemoMode, return mAmbientIndicationContainer; } + @Override + public boolean isOccluded() { + return mIsOccluded; + } + public void setOccluded(boolean occluded) { mIsOccluded = occluded; mScrimController.setKeyguardOccluded(occluded); @@ -1901,10 +1561,10 @@ public class StatusBar extends SystemUI implements DemoMode, mWereIconsJustHidden = true; mHandler.postDelayed(() -> { mWereIconsJustHidden = false; - recomputeDisableFlags(true); + mCommandQueue.recomputeDisableFlags(true); }, 500); } else { - recomputeDisableFlags(animate); + mCommandQueue.recomputeDisableFlags(animate); } } if (shouldHideIconsForBouncer) { @@ -1912,20 +1572,21 @@ public class StatusBar extends SystemUI implements DemoMode, } } + public boolean isHeadsUpShouldBeVisible() { + return mHeadsUpAppearanceController.shouldBeVisible(); + } + + //TODO: These can / should probably be moved to NotificationPresenter or ShadeController @Override public void onLaunchAnimationCancelled() { - if (!isCollapsing()) { + if (!mPresenter.isCollapsing()) { onClosingFinished(); } } - public boolean isHeadsUpShouldBeVisible() { - return mHeadsUpAppearanceController.shouldBeVisible(); - } - @Override public void onExpandAnimationFinished(boolean launchIsFullScreen) { - if (!isCollapsing()) { + if (!mPresenter.isCollapsing()) { onClosingFinished(); } if (launchIsFullScreen) { @@ -1935,8 +1596,9 @@ public class StatusBar extends SystemUI implements DemoMode, @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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, @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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - 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 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarWindowController.setPanelVisible(true); visibilityChanged(true); - recomputeDisableFlags(!force /* animate */); + mCommandQueue.recomputeDisableFlags(!force /* animate */); setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); } @@ -2099,12 +1763,12 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @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 class StatusBar extends SystemUI implements DemoMode, } public void dispatchNotificationsPanelTouchEvent(MotionEvent ev) { - if (!panelsEnabled()) { + if (!mCommandQueue.panelsEnabled()) { return; } mNotificationPanel.dispatchTouchEvent(ev); @@ -2173,7 +1837,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void animateExpandNotificationsPanel() { if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); - if (!panelsEnabled()) { + if (!mCommandQueue.panelsEnabled()) { return ; } @@ -2185,7 +1849,7 @@ public class StatusBar extends SystemUI implements DemoMode, @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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, // update low profile if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { - setAreThereNotifications(); + updateAreThereNotifications(); } // ready to unhide @@ -2703,9 +2368,6 @@ public class StatusBar extends SystemUI implements DemoMode, 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 class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, } } else if (ACTION_FAKE_ARTWORK.equals(action)) { if (DEBUG_MEDIA_FAKE_ARTWORK) { - updateMediaMetaData(true, true); + mPresenter.updateMediaMetaData(true, true); } } } @@ -2917,7 +2579,8 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, } @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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @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 class StatusBar extends SystemUI implements DemoMode, } 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 @@ public class StatusBar extends SystemUI implements DemoMode, // 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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,42 +3313,52 @@ public class StatusBar extends SystemUI implements DemoMode, } } - 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 */); } - private void instantCollapseNotificationPanel() { - mNotificationPanel.instantCollapse(); - runPostCollapseRunnables(); + @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 onActivated(ActivatableNotificationView view) { - onActivated((View) view); - mNotificationPanel.setActivatedChild(view); + 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); + } + } + }); } - 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 */); - } + private void instantCollapseNotificationPanel() { + mNotificationPanel.instantCollapse(); + runPostCollapseRunnables(); } @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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, && DozeParameters.getInstance(mContext).shouldControlScreenOff(); mNotificationPanel.resetViews(dozingAnimated); + updateQsExpansionEnabled(); mKeyguardViewMediator.setAodShowing(mDozing); //TODO: make these folks listeners of StatusBarStateController.onDozingChanged @@ -3828,15 +3455,7 @@ public class StatusBar extends SystemUI implements DemoMode, 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 class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @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 class StatusBar extends SystemUI implements DemoMode, } } - 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 @@ public class StatusBar extends SystemUI implements DemoMode, mBouncerShowing = bouncerShowing; if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing); updateHideIconsForBouncer(true /* animate */); - recomputeDisableFlags(true /* animate */); + mCommandQueue.recomputeDisableFlags(true /* animate */); updateScrimController(); } @@ -4273,25 +3698,6 @@ public class StatusBar extends SystemUI implements DemoMode, } @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 @@ public class StatusBar extends SystemUI implements DemoMode, protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class); - private AboveShelfObserver mAboveShelfObserver; - // handling reordering protected VisualStabilityManager mVisualStabilityManager; @@ -4688,7 +4092,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected KeyguardManager mKeyguardManager; - private LockPatternUtils mLockPatternUtils; private DeviceProvisionedController mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); @@ -4707,28 +4110,10 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, }; @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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - 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 @@ public class StatusBar extends SystemUI implements DemoMode, } } - 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 @@ public class StatusBar extends SystemUI implements DemoMode, // 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 class StatusBar extends SystemUI implements DemoMode, } 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 @@ public class StatusBar extends SystemUI implements DemoMode, }, 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 class StatusBar extends SystemUI implements DemoMode, 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 ac3608bc622a..c5603016fc56 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.Dependency; 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 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // 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 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb 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 000000000000..edfc0496149b --- /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 000000000000..06f9658a0902 --- /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 8e32a0b44c28..59bd85eaabd4 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.Paint; 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 class KeyButtonRipple extends Drawable { public void draw(Canvas canvas) { mSupportHardware = canvas.isHardwareAccelerated(); if (mSupportHardware) { - drawHardware((DisplayListCanvas) canvas); + drawHardware((RecordingCanvas) canvas); } else { drawSoftware(canvas); } @@ -147,7 +146,7 @@ public class KeyButtonRipple extends Drawable { 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 7b42dd4c9817..aba23778f08c 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 @@ public interface KeyguardMonitor extends CallbackController<Callback> { 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 10cb09b75c16..5eb0fb76794d 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 @@ import java.util.ArrayList; 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 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback private long mKeyguardFadingAwayDelay; private long mKeyguardFadingAwayDuration; private boolean mKeyguardGoingAway; + private boolean mLaunchTransitionFadingAway; public KeyguardMonitorImpl(Context context) { mContext = context; @@ -123,7 +124,7 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback 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 class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback 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 dd031623f356..aa4782fd864a 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 android.widget.Button; 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 3f85c9d169c7..a69fd5619e99 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.AndroidTestingRunner; 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 @@ public class KeyguardHostViewTest extends SysuiTestCase { @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 a35ca46833e7..a58bc8548bd4 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 @@ public abstract class SysuiTestCase { @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 9d3124e9ecc6..e811270a4450 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 class SysuiTestableContext extends TestableContext implements SysUiServic 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 5c83d99b646a..0c8d137569f8 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 @@ public class TestableDependency extends Dependency { 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 class TestableDependency extends Dependency { } 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 a02ef98f834d..8ae3cd8d6acd 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 class CommandQueueTest extends SysuiTestCase { 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 da59450af4df..2e280d336aab 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 @@ import org.mockito.MockitoAnnotations; */ @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 @@ public class NonPhoneDependencyTest extends SysuiTestCase { 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 7b0c0a077332..63ececbe2994 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.support.test.filters.SmallTest; 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 @@ import org.mockito.MockitoAnnotations; @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 @@ public class NotificationListenerTest extends SysuiTestCase { 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 515c10980ff6..f168a490acf4 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.support.test.filters.SmallTest; 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 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { 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 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @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 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { 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 8a59e968d16e..d409e2b254df 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.support.test.filters.SmallTest; 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 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { 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 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { 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 class NotificationRemoteInputManagerTest extends SysuiTestCase { } 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 6b4ccc4a80b5..602e613388fd 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.View; 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.ExpandableNotificationRow 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 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @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 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { 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 17daaacded87..1d977d8c5dad 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 @@ public class SmartReplyControllerTest extends SysuiTestCase { 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 78be783da17b..b405a5cd91bf 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 @@ package com.android.systemui.statusbar.notification; 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.support.test.filters.SmallTest; 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 @@ public class AppOpsListenerTest extends SysuiTestCase { 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 @@ public class AppOpsListenerTest extends SysuiTestCase { @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 @@ public class AppOpsListenerTest extends SysuiTestCase { @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 de5a8a0a6d2d..459dc5d43c2c 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.AndroidTestingRunner; 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 @@ public class NotificationDataTest extends SysuiTestCase { @Mock ForegroundServiceController mFsc; @Mock - NotificationData.Environment mEnvironment; + NotificationData.KeyguardEnvironment mEnvironment; private final IPackageManager mMockPackageManager = mock(IPackageManager.class); private NotificationData mNotificationData; @@ -108,10 +111,14 @@ public class NotificationDataTest extends SysuiTestCase { .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 @@ public class NotificationDataTest extends SysuiTestCase { 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 @@ public class NotificationDataTest extends SysuiTestCase { } 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 f01ae7a23533..fb4ecd1383c4 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 android.widget.FrameLayout; 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.NotificationRemoteInputManager; 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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { 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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); + mDependency.injectMockDependency(ShadeController.class); mDependency.injectTestDependency(ForegroundServiceController.class, mForegroundServiceController); mDependency.injectTestDependency(NotificationLockscreenUserManager.class, @@ -204,12 +210,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase { 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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { 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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @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 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @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 ca62c3b5ee6f..1c7a8e8185a3 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 @@ public class NotificationLoggerTest extends SysuiTestCase { 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 cfc75261123a..bf8eb6216d7d 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 android.app.NotificationManager.IMPORTANCE_DEFAULT; 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.AppOpsManager; 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 com.android.systemui.statusbar.notification.stack.NotificationChildrenCon 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 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @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 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { 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 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { } @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 8edbf176215a..ee35449e05da 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.NotificationData; 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 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @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 @@ public class NotificationGutsManagerTest extends SysuiTestCase { 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 150d9337d4a4..fdb66cca92b2 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 android.widget.RemoteViews; 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 @@ public class NotificationInflaterTest extends SysuiTestCase { 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 @@ public class NotificationInflaterTest extends SysuiTestCase { 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 @@ public class NotificationInflaterTest extends SysuiTestCase { 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 f8b24363da8f..d2fe82fd93c4 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.assertEquals; 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.filters.SmallTest; 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.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.ArrayList; + /** * Tests for {@link NotificationStackScrollLayout}. */ @@ -108,6 +113,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { 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 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { 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 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { 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 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { assertEquals(0, mNotificationData.getActiveNotifications().size()); mStackScroller.updateFooter(); - verify(mStackScroller).updateFooterView(false, false); + verify(mStackScroller, atLeastOnce()).updateFooterView(false, false); } @Test @@ -287,7 +295,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { 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 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { } 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 000000000000..96f1976f2b20 --- /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 020682b6b4e8..7f8668fa064c 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.DejankUtils; 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 @@ public class KeyguardBouncerTest extends SysuiTestCase { @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 000000000000..be26d9101c69 --- /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 be4560b5b845..93dedfbe9656 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.testing.TestableLooper; 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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @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 000000000000..24baa7d770f1 --- /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 000000000000..f28757f516da --- /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 da93327061a8..939245f7cc7e 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 @@ package com.android.systemui.statusbar.phone; 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.MetricsLogger; 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 @@ public class StatusBarTest extends SysuiTestCase { @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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { } @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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { } @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 @@ public class StatusBarTest extends SysuiTestCase { @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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { 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 @@ public class StatusBarTest extends SysuiTestCase { NotificationViewHierarchyManager viewHierarchyManager, TestableNotificationEntryManager entryManager, ScrimController scrimController, BiometricUnlockController biometricUnlockController, - ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator, + KeyguardViewMediator keyguardViewMediator, NotificationRemoteInputManager notificationRemoteInputManager, NotificationGroupManager notificationGroupManager, FalsingManager falsingManager, @@ -636,7 +612,8 @@ public class StatusBarTest extends SysuiTestCase { DozeScrimController dozeScrimController, NotificationShelf notificationShelf, NotificationLockscreenUserManager notificationLockscreenUserManager, - CommandQueue commandQueue) { + CommandQueue commandQueue, + NotificationPresenter notificationPresenter) { mStatusBarKeyguardViewManager = man; mUnlockMethodCache = unlock; mKeyguardIndicationController = key; @@ -653,7 +630,6 @@ public class StatusBarTest extends SysuiTestCase { mEntryManager = entryManager; mScrimController = scrimController; mBiometricUnlockController = biometricUnlockController; - mActivityLaunchAnimator = launchAnimator; mKeyguardViewMediator = keyguardViewMediator; mRemoteInputManager = notificationRemoteInputManager; mGroupManager = notificationGroupManager; @@ -664,6 +640,7 @@ public class StatusBarTest extends SysuiTestCase { 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 01e63070e07d..4534ebee52be 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.view.ViewGroup; 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 51b86c26dff2..95c7a4d09f92 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 @@ public class FakeKeyguardMonitor implements KeyguardMonitor { } @Override + public boolean isLaunchTransitionFadingAway() { + return false; + } + + @Override public long getKeyguardFadingAwayDuration() { return 0; } diff --git a/services/art-profile b/services/art-profile index 4168a3f4b28c..742ca1c94a77 100644 --- a/services/art-profile +++ b/services/art-profile @@ -2082,6 +2082,22 @@ HPLcom/android/server/usage/StorageStatsService;->queryStatsForPackage(Ljava/lan 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 af33cbc0ac1c..38b9647c15b4 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -285,14 +285,21 @@ class AlarmManagerService extends SystemService { @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 0b30ff5cc398..af9d4c8c69b6 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.IMaintenanceActivityListener; 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 @@ import java.util.Arrays; 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 @@ import java.util.Arrays; ] 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 @@ import java.util.Arrays; 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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService /** 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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService 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 class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService !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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService @VisibleForTesting boolean isScreenOn() { - return mScreenOn; + synchronized (this) { + return mScreenOn; + } } void updateInteractivityLocked() { @@ -2235,7 +2299,9 @@ public class DeviceIdleController extends SystemService @VisibleForTesting boolean isCharging() { - return mCharging; + synchronized (this) { + return mCharging; + } } void updateChargingLocked(boolean charging) { @@ -2253,6 +2319,27 @@ public class DeviceIdleController extends SystemService } } + @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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService // 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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService 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 @@ public class DeviceIdleController extends SystemService 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 6677541b1b32..2dee3a0b5c21 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.ShellCommand; 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 @@ public class LooperStatsService extends Binder { @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 4070bca199e0..405a2d0ca478 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 000000000000..4e1435e14679 --- /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 4eb964ab461d..1b74ed04f770 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_DISABLE_HIDDEN_API_CHECKS; 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 @@ public class ActivityManagerService extends IActivityManager.Stub */ 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } - final SparseArray<PendingTempWhitelist> mPendingTempWhitelist = new SparseArray<>(); + final PendingTempWhitelists mPendingTempWhitelist = new PendingTempWhitelists(this); /** * Information about and control over application operations @@ -2118,6 +2117,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub "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 @@ public class ActivityManagerService extends IActivityManager.Stub } 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 @@ public class ActivityManagerService extends IActivityManager.Stub } 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } } - 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub @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 45a06524745a..fa227a27dced 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 @@ class ActivityStarter { 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 f79d9aa9ba67..02707fb9aff1 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 @@ package com.android.server.am; 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.REMOVE_TASKS; 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_IN_PLACE; 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.HEA 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_SWITC 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final ActivityThread mSystemThread; H mH; UiHandler mUiHandler; - ActivityManagerService mAm; ActivityManagerInternal mAmInternal; UriGrantsManagerInternal mUgmInternal; private PackageManagerInternal mPmInternal; @@ -347,6 +348,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } // 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * @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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 000000000000..b36e3c7b9e35 --- /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 cb6061a47351..805b979b4bb7 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 @@ public final class ProcessList { } 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 @@ public final class ProcessList { 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 3b859edd3cf9..6cb1097c7ddf 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 @@ package com.android.server.am; 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.ProtoOutputStream; 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 @@ public final class UidRecord { 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 @@ public final class UidRecord { 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 @@ public final class UidRecord { 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 @@ public final class UidRecord { 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 1743ddeedd91..94f10022d10c 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.os.RemoteException; 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 @@ import java.util.ArrayList; * 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio mListener = listener; mAtm = atm; mLastReportedConfiguration = new Configuration(); + mDisplayId = INVALID_DISPLAY; if (config != null) { onConfigurationChanged(config); } @@ -704,6 +711,30 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 5698fdf439a8..5ed626342d31 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 @@ public final class ContentService extends IContentService.Stub { } @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 8c35e27671eb..5cbe5b958b7d 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.app.job.JobParameters; 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 class SyncLogger { */ 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 @@ public class SyncLogger { 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 @@ public class SyncLogger { 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 @@ public class SyncLogger { } 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 d57214ea894c..e37153eb4f7a 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.Resources; 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.Printer; 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub }; private void restoreNonVrImeFromSettingsNoCheck() { + mIsVrImeStarted = false; // switch back to non-VR InputMethod from settings. synchronized (mMethodMap) { final String lastInputId = mSettings.getSelectedInputMethod(); @@ -600,6 +605,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 99a04d7b144f..1d0ab8fc7641 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 @@ public class ContextHubClientBroker extends IContextHubClient.Stub } /** + * @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/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index e6a018a9f39d..45cb477cb4f3 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -1194,6 +1194,7 @@ public final class DefaultPermissionGrantPolicy { } else { permissions.clear(); } + permissions.add(permissionGrant.name); grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId); } } @@ -1359,7 +1360,7 @@ public final class DefaultPermissionGrantPolicy { private boolean isPermissionDangerous(String name) { try { final PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(name, 0); - return (pi.getProtectionFlags() & PermissionInfo.PROTECTION_DANGEROUS) != 0; + return (pi.getProtection() == PermissionInfo.PROTECTION_DANGEROUS); } catch (NameNotFoundException e) { // When unknown assume it's dangerous to be on the safe side return true; diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index ed2b79e7380c..4f8e6b650e24 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 @@ public class BatterySaverPolicy extends ContentObserver { 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 @@ public class BatterySaverPolicy extends ContentObserver { 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 @@ public class BatterySaverPolicy extends ContentObserver { 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 @@ public class BatterySaverPolicy extends ContentObserver { 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 @@ public class BatterySaverPolicy extends ContentObserver { 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 @@ public class BatterySaverPolicy extends ContentObserver { 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 c162afbf3e61..f10fe5814d0b 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.KernelWakelockReader; 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { }); } + 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 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { 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 7f9ee8405dfc..443d6fe5de74 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 class ActivityTaskManagerInternal { */ 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 b7507a42485c..ef63b9b70b3b 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.content.pm.PackageManager; 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 @@ class TaskSnapshotController { 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 eacbda198aba..f16008de0967 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 7a847f3284d2..ba1d83ee2a53 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 @@ public class KeyValueBackupTaskTest { 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 e6cbb5badb9e..b21b3e42adc3 100644 --- a/services/tests/mockingservicestests/Android.mk +++ b/services/tests/mockingservicestests/Android.mk @@ -20,14 +20,11 @@ LOCAL_MODULE_TAGS := tests 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 877c8fad3086..f85ffc84e788 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.spyOn; 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.IActivityManager; 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.Looper; 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.Answers; 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 @@ public class AlarmManagerServiceTest { private AlarmManagerService mService; @Mock + private ContentResolver mMockResolver; + @Mock private IActivityManager mIActivityManager; @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal; @@ -186,9 +204,11 @@ public class AlarmManagerServiceTest { 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 @@ public class AlarmManagerServiceTest { .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 @@ public class AlarmManagerServiceTest { 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 @@ public class AlarmManagerServiceTest { } @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 @@ public class AlarmManagerServiceTest { () -> (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 8afd788256c1..04a84081bad8 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_MAINTENANCE; 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 @@ public class DeviceIdleControllerTest { private PowerManager mPowerManager; @Mock private PowerManager.WakeLock mWakeLock; + @Mock + private PowerManagerInternal mPowerManagerInternal; class InjectorForTest extends DeviceIdleController.Injector { ConnectivityService connectivityService; @@ -204,12 +207,15 @@ public class DeviceIdleControllerTest { .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 @@ public class DeviceIdleControllerTest { } @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 @@ public class DeviceIdleControllerTest { } @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 @@ public class DeviceIdleControllerTest { } @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 class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { @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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); } + ///////////////// EXIT conditions /////////////////// + @Test public void testExitMaintenanceEarlyIfNeededLocked_deep_noActiveOps() { mDeviceIdleController.setJobsActive(false); @@ -766,6 +864,10 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { enterDeepState(STATE_IDLE_MAINTENANCE); mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked(); verifyStateConditions(STATE_IDLE_MAINTENANCE); + + enterDeepState(STATE_QUICK_DOZE_DELAY); + mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked(); + verifyStateConditions(STATE_QUICK_DOZE_DELAY); } @Test @@ -1030,39 +1144,100 @@ public class DeviceIdleControllerTest { } @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 public void testHandleMotionDetectedLocked_light() { enterLightState(LIGHT_STATE_ACTIVE); mDeviceIdleController.handleMotionDetectedLocked(50, "test"); @@ -1128,6 +1303,10 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 @@ public class DeviceIdleControllerTest { 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 26e77eb166ca..8f39b4ab11d3 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.IBinder; 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 @@ import java.util.Collections; @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 9a7488e42326..8c27e256456f 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 @@ public class ActivityManagerInternalTest { 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 f42f5b1fff2e..349c0a37a4c1 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 @@ public class ActivityManagerServiceTest { } 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 @@ public class ActivityManagerServiceTest { 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 @@ public class ActivityManagerServiceTest { @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 @@ public class ActivityManagerServiceTest { 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 @@ public class ActivityManagerServiceTest { 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 @@ public class ActivityManagerServiceTest { @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 @@ public class ActivityManagerServiceTest { @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 @@ public class ActivityManagerServiceTest { 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 65e4fa0f4aff..270d394ead34 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 @@ public class ActivityStartInterceptorTest { @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 d4bab2ef2a43..2fb10e13ab0b 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 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { } /** + * 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 000000000000..0328621ce5d1 --- /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 bd4a356fcb5c..77f6a23c26b1 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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { + "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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { } @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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { 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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { 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 @@ public class BatterySaverPolicyTest extends AndroidTestCase { 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 5a787ec1cff3..473682d4d906 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 @@ public class UsageStatsDatabaseTest { 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 @@ public class UsageStatsDatabaseTest { 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 @@ public class UsageStatsDatabaseTest { 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 @@ public class UsageStatsDatabaseTest { } 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 @@ public class UsageStatsDatabaseTest { } /** + * 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 @@ public class UsageStatsDatabaseTest { 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 8946d251c61d..0e15947abf52 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 @@ import java.util.List; * 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 @@ public class UsageStatsDatabase { // 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { }; 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { } } } 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { } } - // 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 @@ public class UsageStatsDatabase { } 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { } } 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { /* 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 @@ public class UsageStatsDatabase { } - 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { 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 @@ public class UsageStatsDatabase { return; } sanitizeIntervalStatsForBackup(stats); - byte[] data = serializeIntervalStats(stats); + byte[] data = serializeIntervalStats(stats, version); out.writeInt(data.length); out.write(data); } @@ -1165,26 +1179,26 @@ public class UsageStatsDatabase { 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 bafb0a2fd683..ad2501d7c8cf 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 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } + 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 7c22613664a5..d57fcb105f9b 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 @@ public class SoundTriggerService extends SystemService { } 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 3b4016437e9a..7f87c4df8313 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2206,24 +2206,25 @@ public class SubscriptionManager { } /** - * 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 0ccd748c31df..85b4941cf971 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 @@ interface ISub { 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 5bc8934279d6..571f623aea99 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.Canvas; 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 @@ public class CirclePropActivity extends Activity { 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 af8e10bc07ae..220016aa8ab7 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 7713f5da36ed..e7d7f2b11801 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.Canvas; 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 @@ public class MultiProducerActivity extends Activity implements OnClickListener { } // 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 @@ public class MultiProducerActivity extends Activity implements OnClickListener { } // 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 be5d7f98783d..4eb40722f6dd 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.os.Bundle; 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 2ae960bd08db..9abd7ea5f361 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/aapt/Package.cpp b/tools/aapt/Package.cpp index d631f3531127..f06643dcf784 100644 --- a/tools/aapt/Package.cpp +++ b/tools/aapt/Package.cpp @@ -28,7 +28,7 @@ static const char* kExcludeExtension = ".EXCLUDE"; /* these formats are already compressed, or don't compress well */ static const char* kNoCompressExt[] = { - ".jpg", ".jpeg", ".png", ".gif", + ".jpg", ".jpeg", ".png", ".gif", ".opus", ".wav", ".mp2", ".mp3", ".ogg", ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index d1f42f8b398e..257043b30704 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -47,7 +47,8 @@ AtomDecl::AtomDecl(const AtomDecl& that) 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 @@ java_type(const FieldDescriptor* field) } 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 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, 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 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, 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 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, 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 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, // 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 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, 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 31b8b07472cc..450b30547c21 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -89,6 +89,8 @@ struct AtomDecl { 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 56c842805190..1ef34b9c22eb 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -66,6 +66,8 @@ cpp_type_name(java_type_t type) return "double"; case JAVA_TYPE_STRING: return "char const*"; + case JAVA_TYPE_BYTE_ARRAY: + return "char const*"; default: return "UNKNOWN"; } @@ -88,6 +90,8 @@ java_type_name(java_type_t type) return "double"; case JAVA_TYPE_STRING: return "java.lang.String"; + case JAVA_TYPE_BYTE_ARRAY: + return "byte[]"; default: return "UNKNOWN"; } @@ -198,13 +202,40 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, } 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 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio 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 @@ static void write_java_usage(FILE* out, const string& method_name, const string& 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 @@ jni_type_name(java_type_t type) return "jdouble"; case JAVA_TYPE_STRING: return "jstring"; + case JAVA_TYPE_BYTE_ARRAY: + return "jbyteArray"; default: return "UNKNOWN"; } @@ -942,6 +980,9 @@ jni_function_name(const string& method_name, const vector<java_type_t>& signatur 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 @@ java_type_signature(java_type_t type) return "D"; case JAVA_TYPE_STRING: return "Ljava/lang/String;"; + case JAVA_TYPE_BYTE_ARRAY: + return "[B"; default: return "UNKNOWN"; } @@ -1081,6 +1124,25 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp 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 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp } 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 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp 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 f6359748a27e..3be87d95df15 100644 --- a/tools/stats_log_api_gen/test.proto +++ b/tools/stats_log_api_gen/test.proto @@ -109,6 +109,28 @@ message BadAttributionNodePosition { 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 1936d9667948..ad3bffacd442 100644 --- a/tools/stats_log_api_gen/test_collation.cpp +++ b/tools/stats_log_api_gen/test_collation.cpp @@ -212,5 +212,19 @@ TEST(CollationTest, PassOnGoodStateAtomOptions) { 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 |