diff options
221 files changed, 6052 insertions, 3379 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 21bab7cf5d1e..1c3ee82dbba0 100755 --- a/api/current.txt +++ b/api/current.txt @@ -1199,6 +1199,7 @@ package android { field public static final deprecated int selectedWeekBackgroundColor = 16843586; // 0x1010342 field public static final int sessionService = 16843837; // 0x101043d field public static final int settingsActivity = 16843301; // 0x1010225 + field public static final int settingsSliceUri = 16844179; // 0x1010593 field public static final int setupActivity = 16843766; // 0x10103f6 field public static final int shadowColor = 16843105; // 0x1010161 field public static final int shadowDx = 16843106; // 0x1010162 @@ -6321,6 +6322,7 @@ package android.app { method public android.content.pm.ServiceInfo getServiceInfo(); method public java.lang.String getServiceName(); method public java.lang.String getSettingsActivity(); + method public android.net.Uri getSettingsSliceUri(); method public boolean getShowMetadataInPreview(); method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException; method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException; @@ -29743,9 +29745,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); 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/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index c04e61b77274..41d546f6d603 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -174,6 +174,8 @@ public class Am extends BaseCommand { instrument.noWindowAnimation = true; } else if (opt.equals("--no-hidden-api-checks")) { instrument.disableHiddenApiChecks = true; + } else if (opt.equals("--no-isolated-storage")) { + instrument.disableIsolatedStorage = true; } else if (opt.equals("--user")) { instrument.userId = parseUserArg(nextArgRequired()); } else if (opt.equals("--abi")) { diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java index 0dade0b2ba81..70baa8702ba9 100644 --- a/cmds/am/src/com/android/commands/am/Instrument.java +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -16,6 +16,9 @@ package com.android.commands.am; +import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; +import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; + import android.app.IActivityManager; import android.app.IInstrumentationWatcher; import android.app.Instrumentation; @@ -74,16 +77,13 @@ public class Instrument { String logPath = null; public boolean noWindowAnimation = false; public boolean disableHiddenApiChecks = false; + public boolean disableIsolatedStorage = false; public String abi = null; public int userId = UserHandle.USER_CURRENT; public Bundle args = new Bundle(); // Required public String componentNameArg; - // Disable hidden API checks for the newly started instrumentation. - // Must be kept in sync with ActivityManagerService. - private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0; - /** * Construct the instrument command runner. */ @@ -480,7 +480,13 @@ public class Instrument { } // Start the instrumentation - int flags = disableHiddenApiChecks ? INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS : 0; + int flags = 0; + if (disableHiddenApiChecks) { + flags |= INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; + } + if (disableIsolatedStorage) { + flags |= INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; + } if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId, abi)) { throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk index db864aed6bdc..eba558653b04 100644 --- a/cmds/incidentd/Android.mk +++ b/cmds/incidentd/Android.mk @@ -33,6 +33,9 @@ LOCAL_SRC_FILES := $(call all-cpp-files-under, src) \ LOCAL_CFLAGS += \ -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter +# Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed. +LOCAL_CFLAGS += -Wno-error=implicit-fallthrough + ifeq (debug,) LOCAL_CFLAGS += \ -g -O0 @@ -100,6 +103,9 @@ LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -Werror -Wall -Wno-unused-variable -Wunused-parameter +# Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed. +LOCAL_CFLAGS += -Wno-error=implicit-fallthrough + LOCAL_C_INCLUDES += $(LOCAL_PATH)/src LOCAL_SRC_FILES := $(call all-cpp-files-under, tests) \ diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c2fed66eea41..869c3a3c5ea7 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -144,6 +144,7 @@ message Atom { PhoneServiceStateChanged phone_service_state_changed = 94; PhoneStateChanged phone_state_changed = 95; UserRestrictionChanged user_restriction_changed = 96; + SettingsUIChanged settings_ui_changed = 97; } // Pulled events will start at field 10000. @@ -1437,6 +1438,79 @@ message PhoneStateChanged { } /** + * Logs when Settings UI has changed. + * + * Logged from: + * packages/apps/Settings + */ +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; + + // 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; + } + + /** + * 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; + + /** + * What the UI action is. + */ + optional Action action = 2; + + /** + * Where the action is happening + */ + optional PageId pageId = 3; + + /** + * What preference changed in this event. + */ + optional string changedPreferenceKey = 4; + + /** + * The new value of the changed preference. + */ + optional int64 changedPreferenceIntValue = 5; +} + +/** * Logs that a setting was updated. * Logged from: * frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -2051,25 +2125,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; - // Time since notification was created in milliseconds. - optional int64 since_create_millis = 11; + // Reason for dismissal of a notification. This field is only meaningful for + // TYPE_DISMISS events. + optional int32 dismiss_reason = 12; - // Time since notification was interrupted in milliseconds. - optional int64 since_interruption_millis = 12; + // The first post time of notification, stable across updates. + optional int64 creation_millis = 13; - // Time since notification was updated in milliseconds. - optional int64 since_update_millis = 13; + // The most recent interruption time, or the creation time if no updates. + // Differs from update_millis because updates are filtered based on whether + // they actually interrupted the user. + optional int64 interruption_millis = 14; - // Time since notification was visible in milliseconds. - optional int64 since_visible_millis = 14; + // The most recent update time, or the creation time if no updates. + optional int64 update_millis = 15; + + // The most recent visibility event. + optional int64 visible_millis = 16; } @@ -3046,4 +3129,4 @@ message UserRestrictionChanged { optional string restriction = 1; // Whether the restriction is enabled or disabled. optional bool enabled = 2; -}
\ No newline at end of file +} 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/ActivityManager.java b/core/java/android/app/ActivityManager.java index 14b8ae45d989..7330da323f47 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -137,6 +137,17 @@ public class ActivityManager { private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100; private static final int LAST_START_NON_FATAL_ERROR_CODE = 199; + /** + * Disable hidden API checks for the newly started instrumentation. + * @hide + */ + public static final int INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0; + /** + * Mount full external storage for the newly started instrumentation. + * @hide + */ + public static final int INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL = 1 << 1; + static final class UidObserver extends IUidObserver.Stub { final OnUidImportanceListener mListener; final Context mContext; diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index 9873a8152b3f..e33d1fed4b4c 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -16,6 +16,7 @@ package android.app; +import android.app.slice.Slice; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -77,6 +78,7 @@ public final class WallpaperInfo implements Parcelable { final int mContextDescriptionResource; final boolean mShowMetadataInPreview; final boolean mSupportsAmbientMode; + final String mSettingsSliceUri; /** * Constructor. @@ -118,7 +120,6 @@ public final class WallpaperInfo implements Parcelable { com.android.internal.R.styleable.Wallpaper); mSettingsActivityName = sa.getString( com.android.internal.R.styleable.Wallpaper_settingsActivity); - mThumbnailResource = sa.getResourceId( com.android.internal.R.styleable.Wallpaper_thumbnail, -1); @@ -140,6 +141,8 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = sa.getBoolean( com.android.internal.R.styleable.Wallpaper_supportsAmbientMode, false); + mSettingsSliceUri = sa.getString( + com.android.internal.R.styleable.Wallpaper_settingsSliceUri); sa.recycle(); } catch (NameNotFoundException e) { @@ -159,6 +162,7 @@ public final class WallpaperInfo implements Parcelable { mContextDescriptionResource = source.readInt(); mShowMetadataInPreview = source.readInt() != 0; mSupportsAmbientMode = source.readInt() != 0; + mSettingsSliceUri = source.readString(); mService = ResolveInfo.CREATOR.createFromParcel(source); } @@ -332,13 +336,28 @@ public final class WallpaperInfo implements Parcelable { * explicit {@link android.content.ComponentName} * composed of {@link #getPackageName} and the class name returned here. * - * <p>A null will be returned if there is no settings activity associated + * <p>{@code null} will be returned if there is no settings activity associated * with the wallpaper. */ public String getSettingsActivity() { return mSettingsActivityName; } + /** + * Returns an URI that provides a settings {@link Slice} for this wallpaper. + * + * <p>{@code null} will be returned if there is no settings Slice URI associated + * with the wallpaper. + * + * @return The URI. + */ + public Uri getSettingsSliceUri() { + if (mSettingsSliceUri == null) { + return null; + } + return Uri.parse(mSettingsSliceUri); + } + public void dump(Printer pw, String prefix) { pw.println(prefix + "Service:"); mService.dump(pw, prefix + " "); @@ -367,6 +386,7 @@ public final class WallpaperInfo implements Parcelable { dest.writeInt(mContextDescriptionResource); dest.writeInt(mShowMetadataInPreview ? 1 : 0); dest.writeInt(mSupportsAmbientMode ? 1 : 0); + dest.writeString(mSettingsSliceUri); mService.writeToParcel(dest, flags); } 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/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/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/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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 3e559d9e106f..0c3a2957e1bc 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -226,25 +226,50 @@ interface IWindowManager int getPreferredOptionsPanelGravity(int displayId); /** - * Lock the device orientation to the specified rotation, or to the - * current rotation if -1. Sensor input will be ignored until - * thawRotation() is called. - * @hide + * Equivalent to calling {@link #freezeDisplayRotation(int, int)} with {@link + * android.view.Display#DEFAULT_DISPLAY} and given rotation. */ void freezeRotation(int rotation); /** - * Release the orientation lock imposed by freezeRotation(). - * @hide + * Equivalent to calling {@link #thawDisplayRotation(int)} with {@link + * android.view.Display#DEFAULT_DISPLAY}. */ void thawRotation(); /** - * Gets whether the rotation is frozen. + * Equivelant to call {@link #isDisplayRotationFrozen(int)} with {@link + * android.view.Display#DEFAULT_DISPLAY}. + */ + boolean isRotationFrozen(); + + /** + * Lock the display orientation to the specified rotation, or to the current + * rotation if -1. Sensor input will be ignored until thawRotation() is called. * + * @param displayId the ID of display which rotation should be frozen. + * @param rotation one of {@link android.view.Surface#ROTATION_0}, + * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180}, + * {@link android.view.Surface#ROTATION_270} or -1 to freeze it to current rotation. + * @hide + */ + void freezeDisplayRotation(int displayId, int rotation); + + /** + * Release the orientation lock imposed by freezeRotation() on the display. + * + * @param displayId the ID of display which rotation should be thawed. + * @hide + */ + void thawDisplayRotation(int displayId); + + /** + * Gets whether the rotation is frozen on the display. + * + * @param displayId the ID of display which frozen is needed. * @return Whether the rotation is frozen. */ - boolean isRotationFrozen(); + boolean isDisplayRotationFrozen(int displayId); /** * Screenshot the current wallpaper layer, including the whole screen. 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..f17a45800aeb 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,7 +891,7 @@ 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) { 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/View.java b/core/java/android/view/View.java index cc58b8928f6e..c82918249531 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; @@ -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..7da31ebe4a17 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; @@ -3120,7 +3122,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 +3136,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/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/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..97896f0f6028 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; @@ -1131,8 +1129,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, 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_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/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9bedab53bb2c..32cf2e8bac86 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7894,6 +7894,9 @@ <!-- Wallpapers optimized and capable of drawing in ambient mode will return true. --> <attr name="supportsAmbientMode" format="boolean" /> + <!-- Uri that specifies a settings Slice for this wallpaper. --> + <attr name="settingsSliceUri" /> + </declare-styleable> <!-- Use <code>dream</code> as the root tag of the XML resource that diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 31212a6ab28f..fd688a72b7ea 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2916,6 +2916,7 @@ <public name="isLightTheme" /> <public name="isSplitRequired" /> <public name="textLocale" /> + <public name="settingsSliceUri" /> </public-group> <public-group type="drawable" first-id="0x010800b4"> diff --git a/core/tests/packagemanagertests/src/android/content/pm/KernelPackageMappingTests.java b/core/tests/packagemanagertests/src/android/content/pm/KernelPackageMappingTests.java index 1097bc731de8..01382aae923e 100644 --- a/core/tests/packagemanagertests/src/android/content/pm/KernelPackageMappingTests.java +++ b/core/tests/packagemanagertests/src/android/content/pm/KernelPackageMappingTests.java @@ -17,14 +17,9 @@ package android.content.pm; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import android.content.Context; import android.os.FileUtils; -import android.os.Process; import android.os.ServiceManager; import android.os.UserManager; import android.support.test.InstrumentationRegistry; @@ -32,7 +27,6 @@ import android.support.test.runner.AndroidJUnit4; import android.util.Log; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -86,12 +80,23 @@ public class KernelPackageMappingTests { } @Test + public void testSharedInstalledPrimary() throws Exception { + assertEquals("1001", getContent(getKernelPackageFile("shared:android.uid.phone", "appid"))); + } + + @Test public void testInstalledAll() throws Exception { assertEquals("", getContent(getKernelPackageFile("com.android.settings", "excluded_userids"))); } @Test + public void testSharedInstalledAll() throws Exception { + assertEquals("", getContent(getKernelPackageFile("shared:android.uid.phone", + "excluded_userids"))); + } + + @Test public void testNotInstalledSecondary() throws Exception { mSecondaryUser = getUserManager().createUser("Secondary", 0); assertEquals(Integer.toString(mSecondaryUser.id), 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..364fb04e57b1 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; @@ -1297,7 +1295,7 @@ public final class Bitmap implements Parcelable { node.setLeftTopRightBottom(0, 0, width, height); node.setClipToBounds(false); node.setAllowForceDark(false); - final DisplayListCanvas canvas = node.start(width, height); + 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..60641d82cb65 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); } @@ -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/Android.bp b/libs/hwui/Android.bp index 503951d1adc6..f0053a48ae3d 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -231,6 +231,9 @@ cc_defaults { "protos/graphicsstats.proto", ], + // Allow implicit fallthroughs in HardwareBitmapUploader.cpp until they are fixed. + cflags: ["-Wno-implicit-fallthrough"], + proto: { export_proto_headers: true, }, 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/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index e3c97ce686d9..524dfb0fe4ef 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -288,7 +288,7 @@ void parseOptions(int argc, char* argv[]) { case '?': fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]); - // fall-through + [[fallthrough]]; default: error = true; break; 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/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/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/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/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/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index bb059809be2b..1e61a77a76cf 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -47,6 +47,12 @@ public interface DozeHost { void onIgnoreTouchWhilePulsing(boolean ignore); + /** + * If the device was waken up by a passive interrupt that will show the lock screen without + * expanding the notification panel/shade. + */ + void setPassiveInterrupt(boolean lightInterrupt); + interface Callback { /** * Called when a high priority notification is added. diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index cb91d7815be5..d69b1bfa64c3 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -142,6 +142,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeHost.onDoubleTap(screenX, screenY); mMachine.wakeUp(); } else if (isPickup || isWakeLockScreen) { + mDozeHost.setPassiveInterrupt(true); mMachine.wakeUp(); } else { mDozeHost.extendPulse(); @@ -210,6 +211,7 @@ public class DozeTriggers implements DozeMachine.Part { case INITIALIZED: mBroadcastReceiver.register(mContext); mDozeHost.addCallback(mHostCallback); + mDozeHost.setPassiveInterrupt(false); checkTriggersAtInit(); break; case DOZE: @@ -219,6 +221,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors.reregisterAllSensors(); } mDozeSensors.setListening(true); + mDozeHost.setPassiveInterrupt(false); break; case DOZE_AOD_PAUSED: case DOZE_AOD_PAUSING: 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/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index 30d9ef7bd7a3..8526afd34514 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -131,7 +131,7 @@ public class DragDownHelper implements Gefingerpoken { if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild, (int) (y - mInitialTouchY))) { if (mStartingChild == null) { - mDragDownCallback.setEmptyDragAmount(0f); + cancelExpansion(); } else { mCallback.setUserLockedChild(mStartingChild, false); mStartingChild = null; @@ -206,11 +206,8 @@ public class DragDownHelper implements Gefingerpoken { ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0); anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS); - anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mDragDownCallback.setEmptyDragAmount((Float) animation.getAnimatedValue()); - } + anim.addUpdateListener(animation -> { + mDragDownCallback.setEmptyDragAmount((Float) animation.getAnimatedValue()); }); anim.start(); } 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..67b21e1c8752 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,202 @@ 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, + BiometricUnlockController biometricUnlockController, ScrimController scrimController, + LockscreenWallpaper lockscreenWallpaper) { + mBackdrop = backdrop; + mBackdropFront = backdropFront; + mBackdropBack = backdropBack; + mBiometricUnlockController = biometricUnlockController; + mScrimController = scrimController; + mLockscreenWallpaper = lockscreenWallpaper; + } + + /** + * 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 7fa042655e53..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); @@ -793,7 +795,7 @@ public class NotificationShelf extends ActivatableNotificationView implements private void setOpenedAmount(float openedAmount) { mNoAnimationsInThisFrame = openedAmount == 1.0f && mOpenedAmount == 0.0f; mOpenedAmount = openedAmount; - if (!mAmbientState.isPanelFullWidth()) { + if (!mAmbientState.isPanelFullWidth() || mAmbientState.isDark()) { // We don't do a transformation at all, lets just assume we are fully opened openedAmount = 1.0f; } 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/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..d136c4a24fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -62,6 +62,7 @@ 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; @@ -74,13 +75,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 +113,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 +150,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. = new ArrayList<>(); private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; - private final class NotificationClicker implements View.OnClickListener { @Override @@ -159,7 +159,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 +232,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 +313,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 +329,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 +391,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 +430,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 +555,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 +590,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 +645,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 +676,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row) { - row.setNeedsRedaction(mLockscreenUserManager.needsRedaction(entry)); + row.setNeedsRedaction( + Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry)); boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey()); boolean isUpdate = mNotificationData.get(entry.key) != null; boolean wasLowPriority = row.isLowPriority(); @@ -818,7 +862,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 +877,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 +962,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 +1043,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 +1121,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/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/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 0bc54a33347c..c9cbb40317da 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 @@ -44,7 +44,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 +87,33 @@ 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.VisibilityLocationProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; -import com.android.systemui.statusbar.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 +124,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; @@ -435,6 +435,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 +456,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); @@ -4740,7 +4743,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 +4946,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return; } - mStatusBar.addPostCollapseAction(() -> { + mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); for (ExpandableNotificationRow rowToRemove : viewsToRemove) { if (canChildBeDismissed(rowToRemove)) { @@ -5042,6 +5046,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 */ @@ -5654,19 +5662,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override public boolean onDraggedDown(View startingChild, int dragLengthY) { if (mStatusBarState == StatusBarState.KEYGUARD - && hasActiveNotifications() && (!mStatusBar.isDozing() - || mStatusBar.isPulsing())) { + && hasActiveNotifications()) { mLockscreenGestureLogger.write( MetricsEvent.ACTION_LS_SHADE, (int) (dragLengthY / mDisplayMetrics.density), 0 /* velocityDp - N/A */); - // We have notifications, go to locked shade. - mStatusBar.goToLockedShade(startingChild); - if (startingChild instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; - row.onExpandedByGesture(true /* drag down is always an open */); + if (mNotificationPanel.onDraggedDown() || startingChild != null) { + // We have notifications, go to locked shade. + mShadeController.goToLockedShade(startingChild); + if (startingChild instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; + row.onExpandedByGesture(true /* drag down is always an open */); + } } + return true; } else { // abort gesture. 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/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/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 072343a8b101..32c930132977 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -787,6 +787,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 33bc164d807c..836a55fde0f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -108,11 +108,7 @@ public class KeyguardClockPositionAlgorithm { * Dozing and receiving a notification (AOD notification.) */ private boolean mPulsing; - - /** - * Distance in pixels between the top of the screen and the first view of the bouncer. - */ - private int mBouncerTop; + private float mEmptyDragAmount; /** * Refreshes the dimension values. @@ -131,9 +127,8 @@ public class KeyguardClockPositionAlgorithm { } public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight, - float panelExpansion, int parentHeight, - int keyguardStatusHeight, float dark, boolean secure, boolean pulsing, - int bouncerTop) { + float panelExpansion, int parentHeight, int keyguardStatusHeight, float dark, + boolean secure, boolean pulsing, float emptyDragAmount) { mMinTopMargin = minTopMargin + mContainerTopPadding; mMaxShadeBottom = maxShadeBottom; mNotificationStackHeight = notificationStackHeight; @@ -143,7 +138,7 @@ public class KeyguardClockPositionAlgorithm { mDarkAmount = dark; mCurrentlySecure = secure; mPulsing = pulsing; - mBouncerTop = bouncerTop; + mEmptyDragAmount = emptyDragAmount; } public void run(Result result) { @@ -194,15 +189,14 @@ public class KeyguardClockPositionAlgorithm { } float clockYRegular = getExpandedClockPosition(); - boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop; - float clockYTarget = mCurrentlySecure && hasEnoughSpace ? - mMinTopMargin : -mKeyguardStatusHeight; + float clockYBouncer = -mKeyguardStatusHeight; // Move clock up while collapsing the shade float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(mPanelExpansion); - final float clockY = MathUtils.lerp(clockYTarget, clockYRegular, shadeExpansion); + float clockY = MathUtils.lerp(clockYBouncer, clockYRegular, shadeExpansion); + clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion); - return (int) MathUtils.lerp(clockY, clockYDark, mDarkAmount); + return (int) (MathUtils.lerp(clockY, clockYDark, mDarkAmount) + mEmptyDragAmount); } /** 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..f105f6121709 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -95,6 +95,7 @@ import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyButtonDrawable; import com.android.systemui.statusbar.policy.KeyButtonView; import com.android.systemui.statusbar.policy.RotationLockController; @@ -126,6 +127,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { /** 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; @@ -725,7 +729,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } private boolean shouldDisableNavbarGestures() { - return !mStatusBar.isDeviceProvisioned() + return !mDeviceProvisionedController.isDeviceProvisioned() || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0; } 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..a2bd00eae6c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -350,7 +350,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); @@ -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) { @@ -807,7 +809,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 +823,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()); } @@ -1117,7 +1123,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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 75077029c16b..5ee08237e228 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; @@ -38,6 +39,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.os.PowerManager; +import android.os.SystemProperties; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; @@ -64,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; @@ -104,6 +108,11 @@ public class NotificationPanelView extends PanelView implements private static final boolean DEBUG = false; + private static final boolean EXPAND_ON_WAKE_UP = SystemProperties.getBoolean( + "persist.sysui.expand_shade_on_wake_up", true); + private static final boolean WAKE_UP_TO_SHADE = SystemProperties.getBoolean( + "persist.sysui.go_to_shade_on_wake_up", true); + /** * Fling expanding QS. */ @@ -280,6 +289,12 @@ public class NotificationPanelView extends PanelView implements */ private float mLinearDarkAmount; + /** + * State where the device isn't dozing anymore, but the lock screen isn't fully awake. + * The screen will be dimmed down with the shade collapsed. + */ + private boolean mSemiAwake; + private float mDarkAmountTarget; private boolean mPulsing; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); @@ -325,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); @@ -335,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) { @@ -573,7 +594,7 @@ public class NotificationPanelView extends PanelView implements mInterpolatedDarkAmount, mStatusBar.isKeyguardCurrentlySecure(), mPulsing, - mBouncerTop); + mEmptyDragAmount); mClockPositionAlgorithm.run(mClockPositionResult); PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X, mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock); @@ -618,7 +639,7 @@ public class NotificationPanelView extends PanelView implements if (suppressedSummary) { continue; } - if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard( + if (!mLockscreenUserManager.shouldShowOnKeyguard( row.getStatusBarNotification())) { continue; } @@ -1235,6 +1256,12 @@ public class NotificationPanelView extends PanelView implements if (keyguardShowing) { updateDozingVisibilities(false /* animate */); } + + // Expand notification shade if the device was is semi-awake state + if (mBarState == StatusBarState.SHADE && isSemiAwake()) { + mNotificationStackScroller.setDark(false /* dark */, false /* animated */, + null /* touchLocation */); + } resetVerticalPanelPosition(); updateQsState(); } @@ -2335,13 +2362,7 @@ public class NotificationPanelView extends PanelView implements } public void setEmptyDragAmount(float amount) { - float factor = 0.8f; - if (mNotificationStackScroller.getNotGoneChildCount() > 0) { - factor = 0.4f; - } else if (!mStatusBar.hasActiveNotifications()) { - factor = 0.4f; - } - mEmptyDragAmount = amount * factor; + mEmptyDragAmount = amount * 0.2f; positionClockAndNotifications(); } @@ -2402,7 +2423,7 @@ public class NotificationPanelView extends PanelView implements return true; case StatusBarState.SHADE_LOCKED: if (!mQsExpanded) { - mStatusBar.goToKeyguard(); + mShadeController.goToKeyguard(); } return true; case StatusBarState.SHADE: @@ -2605,7 +2626,7 @@ public class NotificationPanelView extends PanelView implements } if (showIconsWhenExpanded != mShowIconsWhenExpanded) { mShowIconsWhenExpanded = showIconsWhenExpanded; - mStatusBar.recomputeDisableFlags(false); + mCommandQueue.recomputeDisableFlags(false); } } @@ -2769,11 +2790,14 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setAnimationsEnabled(!disabled); } - public void setDozing(boolean dozing, boolean animate, - PointF wakeUpTouchLocation) { - mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation); + public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation, + boolean passiveInterrupted) { if (dozing == mDozing) return; mDozing = dozing; + mSemiAwake = !EXPAND_ON_WAKE_UP && !mDozing && passiveInterrupted; + if (!mSemiAwake) { + mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation); + } if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) { @@ -2787,24 +2811,38 @@ public class NotificationPanelView extends PanelView implements } else { mDarkAnimator.cancel(); } + if (mSemiAwake) { + setDarkAmount(0, 0); + } } mDarkAmountTarget = darkAmount; - if (animate) { - if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) { - mDarkInterpolator = dozing - ? Interpolators.FAST_OUT_SLOW_IN - : Interpolators.TOUCH_RESPONSE_REVERSE; + if (!mSemiAwake) { + if (animate) { + startDarkAnimation(); + } else { + setDarkAmount(darkAmount, darkAmount); } - mNotificationStackScroller.notifyDarkAnimationStart(dozing); - mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount); - mDarkAnimator.setInterpolator(Interpolators.LINEAR); - mDarkAnimator.setDuration(mNotificationStackScroller.getDarkAnimationDuration(dozing)); - mDarkAnimator.start(); - } else { - setDarkAmount(darkAmount, darkAmount); } } + public boolean isSemiAwake() { + return mSemiAwake; + } + + private void startDarkAnimation() { + if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) { + mDarkInterpolator = mDozing + ? Interpolators.FAST_OUT_SLOW_IN + : Interpolators.TOUCH_RESPONSE_REVERSE; + } + mNotificationStackScroller.notifyDarkAnimationStart(mDozing); + mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, mDozing ? 1 : 0); + mDarkAnimator.setInterpolator(Interpolators.LINEAR); + mDarkAnimator.setDuration( + mNotificationStackScroller.getDarkAnimationDuration(mDozing)); + mDarkAnimator.start(); + } + private void setDarkAmount(float linearAmount, float amount) { mInterpolatedDarkAmount = amount; mLinearDarkAmount = linearAmount; @@ -2875,7 +2913,7 @@ public class NotificationPanelView extends PanelView implements if (hideIcons != mHideIconsDuringNotificationLaunch) { mHideIconsDuringNotificationLaunch = hideIcons; if (!hideIcons) { - mStatusBar.recomputeDisableFlags(true /* animate */); + mCommandQueue.recomputeDisableFlags(true /* animate */); } } } @@ -2943,6 +2981,7 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.updateSpeedBumpIndex(); mNotificationStackScroller.updateFooter(); updateShowEmptyShadeView(); + mNotificationStackScroller.updateIconAreaViews(); } public void onUpdateRowStates() { @@ -2989,4 +3028,26 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setScrimController(scrimController); 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. + * + * @return {@code true} if dragging down should take the user to SHADE_LOCKED. + */ + public boolean onDraggedDown() { + if (isSemiAwake()) { + mSemiAwake = false; + mNotificationStackScroller.setDark(false /* dark */, true /* animate */, + null /* touchLocation */); + startDarkAnimation(); + mStatusBar.updateScrimController(); + + return WAKE_UP_TO_SHADE; + } + return true; + } } 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/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index e3a7b75554d3..1bed26dd3474 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -63,7 +63,7 @@ import java.util.function.Consumer; public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener, Dumpable { - private static final String TAG = "ScrimController"; + static final String TAG = "ScrimController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** @@ -96,6 +96,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo */ public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f; /** + * A scrim varies its opacity based on a busyness factor, for example + * how many notifications are currently visible. + */ + public static final float GRADIENT_SCRIM_DARK_KEYGUARD = 0.80f; + /** * The most common scrim, the one under the keyguard. */ protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA; @@ -361,7 +366,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mExpansionFraction = fraction; final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED - || mState == ScrimState.KEYGUARD; + || mState == ScrimState.KEYGUARD || mState == ScrimState.DARK_KEYGUARD; if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 085f7b6394ef..ade063d9718f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -49,6 +49,8 @@ public enum ScrimState { // fade it out afterwards. mBlankScreen = true; } + } else if (previousState == ScrimState.KEYGUARD) { + mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP; } else { mAnimationDuration = ScrimController.ANIMATION_DURATION; } @@ -59,8 +61,24 @@ public enum ScrimState { @Override public float getBehindAlpha(float busynessFactor) { return MathUtils.map(0 /* start */, 1 /* stop */, - mScrimBehindAlphaKeyguard, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY, - busynessFactor); + mScrimBehindAlphaKeyguard, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY, + busynessFactor); + } + }, + + /** + * On semi-awake lock screen. + */ + DARK_KEYGUARD(7) { + + @Override + public void prepare(ScrimState previousState) { + mBlankScreen = mDisplayRequiresBlanking && previousState != ScrimState.AOD; + mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP; + mCurrentBehindAlpha = ScrimController.GRADIENT_SCRIM_DARK_KEYGUARD; + mCurrentInFrontAlpha = 0; + mCurrentInFrontTint = Color.BLACK; + mCurrentBehindTint = Color.BLACK; } }, 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 cc9adb86a6b4..f56e219b073a 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,7 +651,6 @@ 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 */); setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff, fullscreenStackBounds, dockedStackBounds); @@ -711,7 +665,16 @@ public class StatusBar extends SystemUI implements DemoMode, } // Set up the initial notification state. - mNotificationListener.setUpWithPresenter(this, mEntryManager); + mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel, + mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController, + mScrimController, this); + mAppOpsListener.setUpWithPresenter(mPresenter); + mNotificationListener.setUpWithPresenter(mPresenter); + mNotificationShelf.setOnActivatedListener(mPresenter); + mRemoteInputManager.getController().addCallback(mStatusBarWindowController); + + // set the initial view visibility + Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications); if (DEBUG) { Log.d(TAG, String.format( @@ -724,24 +687,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 { @@ -788,24 +739,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 +786,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow); mHeadsUpAppearanceController.readFrom(oldController); mStatusBarWindow.setStatusBarView(mStatusBarView); - setAreThereNotifications(); + updateAreThereNotifications(); checkBarModes(); }).getFragmentManager() .beginTransaction() @@ -872,13 +808,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,14 +819,16 @@ 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); } + 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, mBiometricUnlockController, + mScrimController, mLockscreenWallpaper); + mKeyguardIndicationController = SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, mStatusBarWindow.findViewById(R.id.keyguard_indication_area), @@ -908,9 +839,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 @@ -1053,6 +981,30 @@ public class StatusBar extends SystemUI implements DemoMode, ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); } + @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 +1036,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 +1043,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 +1113,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); @@ -1234,73 +1176,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 +1219,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 +1249,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 +1344,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 +1384,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 +1457,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 +1504,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 +1542,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 +1553,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 +1577,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 +1591,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 +1656,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 +1698,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 +1711,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 +1744,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 +1800,7 @@ public class StatusBar extends SystemUI implements DemoMode, } public void dispatchNotificationsPanelTouchEvent(MotionEvent ev) { - if (!panelsEnabled()) { + if (!mCommandQueue.panelsEnabled()) { return; } mNotificationPanel.dispatchTouchEvent(ev); @@ -2173,7 +1818,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 +1830,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 +1878,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 +1976,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 +2349,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 +2393,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 +2531,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 +2560,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 +2595,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 +2636,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 +2672,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 +2912,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 +2921,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 +2943,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 +2996,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 +3020,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 +3111,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 +3121,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 +3131,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 +3172,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); @@ -3617,7 +3214,8 @@ public class StatusBar extends SystemUI implements DemoMode, mDozeScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); - mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation); + mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation, + mDozeServiceHost.wasPassivelyInterrupted()); mNotificationLogger.setDozing(mDozing); mGroupManager.setDozing(mDozing); updateQsExpansionEnabled(); @@ -3696,42 +3294,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. @@ -3779,7 +3387,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()); @@ -3796,6 +3404,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 @@ -3827,15 +3436,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(); } @@ -3845,7 +3446,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); @@ -3885,22 +3486,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); @@ -3957,184 +3542,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}. */ @@ -4148,7 +3555,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(); } @@ -4203,7 +3610,6 @@ public class StatusBar extends SystemUI implements DemoMode, mAmbientPulseManager.releaseAllImmediately(); mVisualStabilityManager.setScreenOn(true); mNotificationPanel.setTouchAndAnimationDisabled(false); - mDozeServiceHost.stopDozing(); updateVisibleToUser(); updateIsKeyguard(); updateScrimController(); @@ -4273,25 +3679,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(); } @@ -4401,6 +3788,9 @@ public class StatusBar extends SystemUI implements DemoMode, // FLAG_DISMISS_KEYGUARD_ACTIVITY. ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming() ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER; + if (mNotificationPanel.isSemiAwake()) { + state = ScrimState.DARK_KEYGUARD; + } mScrimController.transitionTo(state); } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn || launchingAffordanceWithPreview) { @@ -4412,7 +3802,8 @@ public class StatusBar extends SystemUI implements DemoMode, } else if (mDozing) { mScrimController.transitionTo(ScrimState.AOD); } else if (mIsKeyguard && !wakeAndUnlocking) { - mScrimController.transitionTo(ScrimState.KEYGUARD); + mScrimController.transitionTo(mNotificationPanel.isSemiAwake() + ? ScrimState.DARK_KEYGUARD : ScrimState.KEYGUARD); } else { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } @@ -4432,6 +3823,7 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mAnimateWakeup; private boolean mAnimateScreenOff; private boolean mIgnoreTouchWhilePulsing; + private boolean mPassivelyInterrupted; @Override public String toString() { @@ -4515,6 +3907,11 @@ public class StatusBar extends SystemUI implements DemoMode, } @Override + public void setPassiveInterrupt(boolean passiveInterrupt) { + mPassivelyInterrupted = passiveInterrupt; + } + + @Override public void onIgnoreTouchWhilePulsing(boolean ignore) { if (ignore != mIgnoreTouchWhilePulsing) { DozeLog.tracePulseTouchDisabledByProx(mContext, ignore); @@ -4633,6 +4030,10 @@ public class StatusBar extends SystemUI implements DemoMode, public boolean shouldAnimateScreenOff() { return mAnimateScreenOff; } + + public boolean wasPassivelyInterrupted() { + return mPassivelyInterrupted; + } } public boolean shouldIgnoreTouch() { @@ -4655,8 +4056,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class); - private AboveShelfObserver mAboveShelfObserver; - // handling reordering protected VisualStabilityManager mVisualStabilityManager; @@ -4674,7 +4073,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected KeyguardManager mKeyguardManager; - private LockPatternUtils mLockPatternUtils; private DeviceProvisionedController mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); @@ -4693,28 +4091,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) { @@ -4740,182 +4120,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 { @@ -4923,7 +4134,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 */, @@ -4936,59 +4148,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(), @@ -5049,7 +4210,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 */); } @@ -5062,24 +4223,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 */ @@ -5091,8 +4234,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(); } @@ -5100,7 +4243,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(), @@ -5134,18 +4277,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); @@ -5262,28 +4394,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..635ffc75182f --- /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/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java index 2398fd3c4712..6abd407afd91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java @@ -115,6 +115,11 @@ class DozeHostFake implements DozeHost { } @Override + public void setPassiveInterrupt(boolean lightInterrupt) { + + } + + @Override public void setDozeScreenBrightness(int value) { } 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..fe0a7c78def1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java @@ -17,7 +17,6 @@ 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; @@ -26,13 +25,15 @@ 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; @@ -49,25 +50,27 @@ import org.mockito.MockitoAnnotations; */ @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) 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 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 +82,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/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/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/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/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/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index d86de5dfd799..da1fee374520 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -6564,6 +6564,11 @@ message MetricsEvent { // OS: Q MOBILE_ROAMING_DIALOG = 1583; + // OPEN: Settings > Display > Lock screen display > On lock screen + // CATEGORY: SETTINGS + // OS: Q + LOCK_SCREEN_NOTIFICATION_CONTENT = 1584; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java index b938f3be4926..17bf5705d489 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java @@ -32,6 +32,8 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.MathUtils; import android.util.Slog; +import android.util.SparseArray; +import android.view.Display; import android.view.MagnificationSpec; import android.view.View; import android.view.animation.DecelerateInterpolator; @@ -40,6 +42,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; +import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.wm.WindowManagerInternal; @@ -55,7 +58,7 @@ import java.util.Locale; * magnification region. If a value is out of bounds, it will be adjusted to guarantee these * constraints. */ -public class MagnificationController implements Handler.Callback { +public class MagnificationController { private static final boolean DEBUG = false; private static final String LOG_TAG = "MagnificationController"; @@ -64,90 +67,553 @@ public class MagnificationController implements Handler.Callback { private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false; - private static final int INVALID_ID = -1; - private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f; - // Messages - private static final int MSG_SEND_SPEC_TO_ANIMATION = 1; - private static final int MSG_SCREEN_TURNED_OFF = 2; - private static final int MSG_ON_MAGNIFIED_BOUNDS_CHANGED = 3; - private static final int MSG_ON_RECTANGLE_ON_SCREEN_REQUESTED = 4; - private static final int MSG_ON_USER_CONTEXT_CHANGED = 5; - private final Object mLock; + private final AccessibilityManagerService mAms; + + private final SettingsBridge mSettingsBridge; + + private final ScreenStateObserver mScreenStateObserver; + + private int mUserId; + + private final long mMainThreadId; + + private Handler mHandler; + + private final WindowManagerInternal mWindowManager; + + private final DisplayMagnification mDisplay; + /** - * The current magnification spec. If an animation is running, this - * reflects the end state. + * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds + * magnification information per display. */ - private final MagnificationSpec mCurrentMagnificationSpec = MagnificationSpec.obtain(); + private final class DisplayMagnification implements + WindowManagerInternal.MagnificationCallbacks { + /** + * The current magnification spec. If an animation is running, this + * reflects the end state. + */ + private final MagnificationSpec mCurrentMagnificationSpec = MagnificationSpec.obtain(); - private final Region mMagnificationRegion = Region.obtain(); - private final Rect mMagnificationBounds = new Rect(); + private final Region mMagnificationRegion = Region.obtain(); + private final Rect mMagnificationBounds = new Rect(); - private final Rect mTempRect = new Rect(); - private final Rect mTempRect1 = new Rect(); + private final Rect mTempRect = new Rect(); + private final Rect mTempRect1 = new Rect(); - private final AccessibilityManagerService mAms; + private final SpecAnimationBridge mSpecAnimationBridge; - private final SettingsBridge mSettingsBridge; + // Flag indicating that we are registered with window manager. + private boolean mRegistered; + private boolean mUnregisterPending; - private final ScreenStateObserver mScreenStateObserver; + private final int mDisplayId; + + private static final int INVALID_ID = -1; + private int mIdOfLastServiceToMagnify = INVALID_ID; - private final SpecAnimationBridge mSpecAnimationBridge; - private final WindowManagerInternal.MagnificationCallbacks mWMCallbacks = - new WindowManagerInternal.MagnificationCallbacks () { - @Override - public void onMagnificationRegionChanged(Region region) { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = Region.obtain(region); - mHandler.obtainMessage(MSG_ON_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget(); + DisplayMagnification(int displayId, SpecAnimationBridge specAnimation) { + mDisplayId = displayId; + mSpecAnimationBridge = specAnimation; + } + + void register() { + synchronized (mLock) { + if (!mRegistered) { + mWindowManager.setMagnificationCallbacks(this); + mSpecAnimationBridge.setEnabled(true); + // Obtain initial state. + mWindowManager.getMagnificationRegion(mMagnificationRegion); + mMagnificationRegion.getBounds(mMagnificationBounds); + mRegistered = true; } + } + } - @Override - public void onRectangleOnScreenRequested(int left, int top, int right, int bottom) { - final SomeArgs args = SomeArgs.obtain(); - args.argi1 = left; - args.argi2 = top; - args.argi3 = right; - args.argi4 = bottom; - mHandler.obtainMessage(MSG_ON_RECTANGLE_ON_SCREEN_REQUESTED, args) - .sendToTarget(); + void unregister() { + synchronized (mLock) { + if (!isMagnifying()) { + unregisterInternalLocked(); + } else { + mUnregisterPending = true; + reset(true); } + } + } + + boolean isRegisteredLocked() { + return mRegistered; + } + + + float getScale() { + return mCurrentMagnificationSpec.scale; + } + + float getOffsetX() { + return mCurrentMagnificationSpec.offsetX; + } + + float getCenterX() { + synchronized (mLock) { + return (mMagnificationBounds.width() / 2.0f + + mMagnificationBounds.left - getOffsetX()) / getScale(); + } + } + + float getCenterY() { + synchronized (mLock) { + return (mMagnificationBounds.height() / 2.0f + + mMagnificationBounds.top - getOffsetY()) / getScale(); + } + } - @Override - public void onRotationChanged(int rotation) { - // Treat as context change and reset - mHandler.sendEmptyMessage(MSG_ON_USER_CONTEXT_CHANGED); + /** + * Returns the scale currently used by the window manager. If an + * animation is in progress, this reflects the current state of the + * animation. + * + * @return the scale currently used by the window manager + */ + float getSentScale() { + return mSpecAnimationBridge.mSentMagnificationSpec.scale; + } + + /** + * Returns the X offset currently used by the window manager. If an + * animation is in progress, this reflects the current state of the + * animation. + * + * @return the X offset currently used by the window manager + */ + float getSentOffsetX() { + return mSpecAnimationBridge.mSentMagnificationSpec.offsetX; + } + + /** + * Returns the Y offset currently used by the window manager. If an + * animation is in progress, this reflects the current state of the + * animation. + * + * @return the Y offset currently used by the window manager + */ + float getSentOffsetY() { + return mSpecAnimationBridge.mSentMagnificationSpec.offsetY; + } + + boolean resetIfNeeded(boolean animate) { + synchronized (mLock) { + if (isMagnifying()) { + reset(animate); + return true; } + return false; + } + } + + float getOffsetY() { + return mCurrentMagnificationSpec.offsetY; + } + + boolean isMagnifying() { + return mCurrentMagnificationSpec.scale > 1.0f; + } + + void unregisterInternalLocked() { + if (mRegistered) { + mSpecAnimationBridge.setEnabled(false); + mWindowManager.setMagnificationCallbacks(null); + mMagnificationRegion.setEmpty(); + + mRegistered = false; + } + mUnregisterPending = false; + } + + + @Override + public void onMagnificationRegionChanged(Region magnificationRegion) { + final Message m = PooledLambda.obtainMessage( + DisplayMagnification.this::updateMagnificationRegion, + Region.obtain(magnificationRegion)); + mHandler.sendMessage(m); + } + + @Override + public void onRectangleOnScreenRequested(int left, int top, int right, int bottom) { + final Message m = PooledLambda.obtainMessage( + DisplayMagnification.this::requestRectangleOnScreen, left, top, right, bottom); + mHandler.sendMessage(m); + } + + @Override + public void onRotationChanged(int rotation) { + // Treat as context change and reset + final Message m = PooledLambda.obtainMessage(DisplayMagnification.this::resetIfNeeded, + true); + mHandler.sendMessage(m); + } - @Override - public void onUserContextChanged() { - mHandler.sendEmptyMessage(MSG_ON_USER_CONTEXT_CHANGED); + @Override + public void onUserContextChanged() { + final Message m = PooledLambda.obtainMessage(DisplayMagnification.this::resetIfNeeded, + true); + mHandler.sendMessage(m); + } + + /** + * Update our copy of the current magnification region + * + * @param magnified the magnified region + */ + void updateMagnificationRegion(Region magnified) { + synchronized (mLock) { + if (!mRegistered) { + // Don't update if we've unregistered + return; } - }; + if (!mMagnificationRegion.equals(magnified)) { + mMagnificationRegion.set(magnified); + mMagnificationRegion.getBounds(mMagnificationBounds); + // It's possible that our magnification spec is invalid with the new bounds. + // Adjust the current spec's offsets if necessary. + if (updateCurrentSpecWithOffsetsLocked( + mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) { + sendSpecToAnimation(mCurrentMagnificationSpec, false); + } + onMagnificationChangedLocked(); + } + magnified.recycle(); + } + } - private int mUserId; + void sendSpecToAnimation(MagnificationSpec spec, boolean animate) { + if (DEBUG) { + Slog.i(LOG_TAG, + "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")"); + } + if (Thread.currentThread().getId() == mMainThreadId) { + mSpecAnimationBridge.updateSentSpecMainThread(spec, animate); + } else { + final Message m = PooledLambda.obtainMessage( + this.mSpecAnimationBridge::updateSentSpecMainThread, spec, animate); + mHandler.sendMessage(m); + } + } - private final long mMainThreadId; + /** + * Get the ID of the last service that changed the magnification spec. + * + * @return The id + */ + int getIdOfLastServiceToMagnify() { + return mIdOfLastServiceToMagnify; + } - private Handler mHandler; + void onMagnificationChangedLocked() { + mAms.notifyMagnificationChanged(mMagnificationRegion, + getScale(), getCenterX(), getCenterY()); + if (mUnregisterPending && !isMagnifying()) { + unregisterInternalLocked(); + } + } - private int mIdOfLastServiceToMagnify = INVALID_ID; + boolean magnificationRegionContains(float x, float y) { + synchronized (mLock) { + return mMagnificationRegion.contains((int) x, (int) y); - private final WindowManagerInternal mWindowManager; + } + } + + void getMagnificationBounds(@NonNull Rect outBounds) { + synchronized (mLock) { + outBounds.set(mMagnificationBounds); + } + } + + void getMagnificationRegion(@NonNull Region outRegion) { + synchronized (mLock) { + outRegion.set(mMagnificationRegion); + } + } + + void requestRectangleOnScreen(int left, int top, int right, int bottom) { + synchronized (mLock) { + final Rect magnifiedFrame = mTempRect; + getMagnificationBounds(magnifiedFrame); + if (!magnifiedFrame.intersects(left, top, right, bottom)) { + return; + } + + final Rect magnifFrameInScreenCoords = mTempRect1; + getMagnifiedFrameInContentCoordsLocked(magnifFrameInScreenCoords); + + final float scrollX; + final float scrollY; + if (right - left > magnifFrameInScreenCoords.width()) { + final int direction = TextUtils + .getLayoutDirectionFromLocale(Locale.getDefault()); + if (direction == View.LAYOUT_DIRECTION_LTR) { + scrollX = left - magnifFrameInScreenCoords.left; + } else { + scrollX = right - magnifFrameInScreenCoords.right; + } + } else if (left < magnifFrameInScreenCoords.left) { + scrollX = left - magnifFrameInScreenCoords.left; + } else if (right > magnifFrameInScreenCoords.right) { + scrollX = right - magnifFrameInScreenCoords.right; + } else { + scrollX = 0; + } + + if (bottom - top > magnifFrameInScreenCoords.height()) { + scrollY = top - magnifFrameInScreenCoords.top; + } else if (top < magnifFrameInScreenCoords.top) { + scrollY = top - magnifFrameInScreenCoords.top; + } else if (bottom > magnifFrameInScreenCoords.bottom) { + scrollY = bottom - magnifFrameInScreenCoords.bottom; + } else { + scrollY = 0; + } + + final float scale = getScale(); + offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_ID); + } + } + + void getMagnifiedFrameInContentCoordsLocked(Rect outFrame) { + final float scale = getSentScale(); + final float offsetX = getSentOffsetX(); + final float offsetY = getSentOffsetY(); + getMagnificationBounds(outFrame); + outFrame.offset((int) -offsetX, (int) -offsetY); + outFrame.scale(1.0f / scale); + } + + /** + * Resets magnification if last magnifying service is disabled. + * + * @param connectionId the connection ID be disabled. + * @return {@code true} on success, {@code false} on failure + */ + boolean resetIfNeeded(int connectionId) { + if (mIdOfLastServiceToMagnify == connectionId) { + return resetIfNeeded(true /*animate*/); + } + return false; + } + + void setForceShowMagnifiableBounds(boolean show) { + if (mRegistered) { + mWindowManager.setForceShowMagnifiableBounds(show); + } + } + + boolean reset(boolean animate) { + synchronized (mLock) { + if (!mRegistered) { + return false; + } + final MagnificationSpec spec = mCurrentMagnificationSpec; + final boolean changed = !spec.isNop(); + if (changed) { + spec.clear(); + onMagnificationChangedLocked(); + } + mIdOfLastServiceToMagnify = INVALID_ID; + sendSpecToAnimation(spec, animate); + return changed; + } + } + + + boolean setScale(float scale, float pivotX, float pivotY, + boolean animate, int id) { + + synchronized (mLock) { + if (!mRegistered) { + return false; + } + // Constrain scale immediately for use in the pivot calculations. + scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + + final Rect viewport = mTempRect; + mMagnificationRegion.getBounds(viewport); + final MagnificationSpec spec = mCurrentMagnificationSpec; + final float oldScale = spec.scale; + final float oldCenterX + = (viewport.width() / 2.0f - spec.offsetX + viewport.left) / oldScale; + final float oldCenterY + = (viewport.height() / 2.0f - spec.offsetY + viewport.top) / oldScale; + final float normPivotX = (pivotX - spec.offsetX) / oldScale; + final float normPivotY = (pivotY - spec.offsetY) / oldScale; + final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale); + final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale); + final float centerX = normPivotX + offsetX; + final float centerY = normPivotY + offsetY; + mIdOfLastServiceToMagnify = id; + + return setScaleAndCenter(scale, centerX, centerY, animate, id); + } + } - // Flag indicating that we are registered with window manager. - @VisibleForTesting boolean mRegistered; + boolean setScaleAndCenter(float scale, float centerX, float centerY, + boolean animate, int id) { - private boolean mUnregisterPending; + synchronized (mLock) { + if (!mRegistered) { + return false; + } + if (DEBUG) { + Slog.i(LOG_TAG, + "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX + + ", centerY = " + centerY + ", animate = " + animate + + ", id = " + id + + ")"); + } + final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY); + sendSpecToAnimation(mCurrentMagnificationSpec, animate); + if (isMagnifying() && (id != INVALID_ID)) { + mIdOfLastServiceToMagnify = id; + } + return changed; + } + } + + /** + * Updates the current magnification spec. + * + * @param scale the magnification scale + * @param centerX the unscaled, screen-relative X coordinate of the center + * of the viewport, or {@link Float#NaN} to leave unchanged + * @param centerY the unscaled, screen-relative Y coordinate of the center + * of the viewport, or {@link Float#NaN} to leave unchanged + * @return {@code true} if the magnification spec changed or {@code false} + * otherwise + */ + boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY) { + // Handle defaults. + if (Float.isNaN(centerX)) { + centerX = getCenterX(); + } + if (Float.isNaN(centerY)) { + centerY = getCenterY(); + } + if (Float.isNaN(scale)) { + scale = getScale(); + } + + // Compute changes. + boolean changed = false; + + final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + if (Float.compare(mCurrentMagnificationSpec.scale, normScale) != 0) { + mCurrentMagnificationSpec.scale = normScale; + changed = true; + } + + final float nonNormOffsetX = mMagnificationBounds.width() / 2.0f + + mMagnificationBounds.left - centerX * normScale; + final float nonNormOffsetY = mMagnificationBounds.height() / 2.0f + + mMagnificationBounds.top - centerY * normScale; + changed |= updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY); + + if (changed) { + onMagnificationChangedLocked(); + } + + return changed; + } + + void offsetMagnifiedRegion(float offsetX, float offsetY, int id) { + synchronized (mLock) { + if (!mRegistered) { + return; + } + + final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX; + final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY; + if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) { + onMagnificationChangedLocked(); + } + if (id != INVALID_ID) { + mIdOfLastServiceToMagnify = id; + } + sendSpecToAnimation(mCurrentMagnificationSpec, false); + } + } + + boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) { + if (DEBUG) { + Slog.i(LOG_TAG, + "updateCurrentSpecWithOffsetsLocked(nonNormOffsetX = " + nonNormOffsetX + + ", nonNormOffsetY = " + nonNormOffsetY + ")"); + } + boolean changed = false; + final float offsetX = MathUtils.constrain( + nonNormOffsetX, getMinOffsetXLocked(), getMaxOffsetXLocked()); + if (Float.compare(mCurrentMagnificationSpec.offsetX, offsetX) != 0) { + mCurrentMagnificationSpec.offsetX = offsetX; + changed = true; + } + final float offsetY = MathUtils.constrain( + nonNormOffsetY, getMinOffsetYLocked(), getMaxOffsetYLocked()); + if (Float.compare(mCurrentMagnificationSpec.offsetY, offsetY) != 0) { + mCurrentMagnificationSpec.offsetY = offsetY; + changed = true; + } + return changed; + } + + float getMinOffsetXLocked() { + final float viewportWidth = mMagnificationBounds.width(); + final float viewportLeft = mMagnificationBounds.left; + return (viewportLeft + viewportWidth) - + (viewportLeft + viewportWidth) * mCurrentMagnificationSpec.scale; + } + + float getMaxOffsetXLocked() { + return mMagnificationBounds.left - + mMagnificationBounds.left * mCurrentMagnificationSpec.scale; + } + + float getMinOffsetYLocked() { + final float viewportHeight = mMagnificationBounds.height(); + final float viewportTop = mMagnificationBounds.top; + return (viewportTop + viewportHeight) - + (viewportTop + viewportHeight) * mCurrentMagnificationSpec.scale; + } + + float getMaxOffsetYLocked() { + return mMagnificationBounds.top - + mMagnificationBounds.top * mCurrentMagnificationSpec.scale; + } + + @Override + public String toString() { + return "DisplayMagnification{" + + "mCurrentMagnificationSpec=" + mCurrentMagnificationSpec + + ", mMagnificationRegion=" + mMagnificationRegion + + ", mMagnificationBounds=" + mMagnificationBounds + + ", mDisplayId=" + mDisplayId + + ", mUserId=" + mUserId + + ", mIdOfLastServiceToMagnify=" + mIdOfLastServiceToMagnify + + ", mRegistered=" + mRegistered + + ", mUnregisterPending=" + mUnregisterPending + + '}'; + } + + } public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) { this(context, ams, lock, null, LocalServices.getService(WindowManagerInternal.class), new ValueAnimator(), new SettingsBridge(context.getContentResolver())); - mHandler = new Handler(context.getMainLooper(), this); + mHandler = new Handler(context.getMainLooper()); } public MagnificationController( @@ -164,9 +630,10 @@ public class MagnificationController implements Handler.Callback { mAms = ams; mScreenStateObserver = new ScreenStateObserver(context, this); mLock = lock; - mSpecAnimationBridge = new SpecAnimationBridge( - context, mLock, mWindowManager, valueAnimator); mSettingsBridge = settingsBridge; + //TODO (multidisplay): Magnification is supported only for the default display. + mDisplay = new DisplayMagnification(Display.DEFAULT_DISPLAY, + new SpecAnimationBridge(context, mLock, mWindowManager, valueAnimator)); } /** @@ -178,16 +645,9 @@ public class MagnificationController implements Handler.Callback { */ public void register() { synchronized (mLock) { - if (!mRegistered) { - mScreenStateObserver.register(); - mWindowManager.setMagnificationCallbacks(mWMCallbacks); - mSpecAnimationBridge.setEnabled(true); - // Obtain initial state. - mWindowManager.getMagnificationRegion(mMagnificationRegion); - mMagnificationRegion.getBounds(mMagnificationBounds); - mRegistered = true; - } + mScreenStateObserver.register(); } + mDisplay.register(); } /** @@ -196,33 +656,18 @@ public class MagnificationController implements Handler.Callback { */ public void unregister() { synchronized (mLock) { - if (!isMagnifying()) { - unregisterInternalLocked(); - } else { - mUnregisterPending = true; - resetLocked(true); - } + mScreenStateObserver.unregister(); } + mDisplay.unregister(); } - + /** * Check if we are registered. Note that we may be planning to unregister at any moment. * * @return {@code true} if the controller is registered. {@code false} otherwise. */ public boolean isRegisteredLocked() { - return mRegistered; - } - - private void unregisterInternalLocked() { - if (mRegistered) { - mSpecAnimationBridge.setEnabled(false); - mScreenStateObserver.unregister(); - mWindowManager.setMagnificationCallbacks(null); - mMagnificationRegion.setEmpty(); - mRegistered = false; - } - mUnregisterPending = false; + return mDisplay.isRegisteredLocked(); } /** @@ -230,32 +675,7 @@ public class MagnificationController implements Handler.Callback { * is > 1, {@code false} otherwise */ public boolean isMagnifying() { - return mCurrentMagnificationSpec.scale > 1.0f; - } - - /** - * Update our copy of the current magnification region - * - * @param magnified the magnified region - */ - private void onMagnificationRegionChanged(Region magnified) { - synchronized (mLock) { - if (!mRegistered) { - // Don't update if we've unregistered - return; - } - if (!mMagnificationRegion.equals(magnified)) { - mMagnificationRegion.set(magnified); - mMagnificationRegion.getBounds(mMagnificationBounds); - // It's possible that our magnification spec is invalid with the new bounds. - // Adjust the current spec's offsets if necessary. - if (updateCurrentSpecWithOffsetsLocked( - mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) { - sendSpecToAnimation(mCurrentMagnificationSpec, false); - } - onMagnificationChangedLocked(); - } - } + return mDisplay.isMagnifying(); } /** @@ -268,9 +688,8 @@ public class MagnificationController implements Handler.Callback { * magnified region, or {@code false} otherwise */ public boolean magnificationRegionContains(float x, float y) { - synchronized (mLock) { - return mMagnificationRegion.contains((int) x, (int) y); - } + return mDisplay.magnificationRegionContains(x, y); + } /** @@ -282,9 +701,7 @@ public class MagnificationController implements Handler.Callback { * region */ public void getMagnificationBounds(@NonNull Rect outBounds) { - synchronized (mLock) { - outBounds.set(mMagnificationBounds); - } + mDisplay.getMagnificationBounds(outBounds); } /** @@ -295,9 +712,7 @@ public class MagnificationController implements Handler.Callback { * @param outRegion the region to populate */ public void getMagnificationRegion(@NonNull Region outRegion) { - synchronized (mLock) { - outRegion.set(mMagnificationRegion); - } + mDisplay.getMagnificationRegion(outRegion); } /** @@ -307,7 +722,7 @@ public class MagnificationController implements Handler.Callback { * @return the scale */ public float getScale() { - return mCurrentMagnificationSpec.scale; + return mDisplay.getScale(); } /** @@ -317,7 +732,7 @@ public class MagnificationController implements Handler.Callback { * @return the X offset */ public float getOffsetX() { - return mCurrentMagnificationSpec.offsetX; + return mDisplay.getOffsetX(); } @@ -328,10 +743,7 @@ public class MagnificationController implements Handler.Callback { * @return the X coordinate */ public float getCenterX() { - synchronized (mLock) { - return (mMagnificationBounds.width() / 2.0f - + mMagnificationBounds.left - getOffsetX()) / getScale(); - } + return mDisplay.getCenterX(); } /** @@ -341,7 +753,7 @@ public class MagnificationController implements Handler.Callback { * @return the Y offset */ public float getOffsetY() { - return mCurrentMagnificationSpec.offsetY; + return mDisplay.getOffsetY(); } /** @@ -351,43 +763,7 @@ public class MagnificationController implements Handler.Callback { * @return the Y coordinate */ public float getCenterY() { - synchronized (mLock) { - return (mMagnificationBounds.height() / 2.0f - + mMagnificationBounds.top - getOffsetY()) / getScale(); - } - } - - /** - * Returns the scale currently used by the window manager. If an - * animation is in progress, this reflects the current state of the - * animation. - * - * @return the scale currently used by the window manager - */ - private float getSentScale() { - return mSpecAnimationBridge.mSentMagnificationSpec.scale; - } - - /** - * Returns the X offset currently used by the window manager. If an - * animation is in progress, this reflects the current state of the - * animation. - * - * @return the X offset currently used by the window manager - */ - private float getSentOffsetX() { - return mSpecAnimationBridge.mSentMagnificationSpec.offsetX; - } - - /** - * Returns the Y offset currently used by the window manager. If an - * animation is in progress, this reflects the current state of the - * animation. - * - * @return the Y offset currently used by the window manager - */ - private float getSentOffsetY() { - return mSpecAnimationBridge.mSentMagnificationSpec.offsetY; + return mDisplay.getCenterY(); } /** @@ -400,24 +776,9 @@ public class MagnificationController implements Handler.Callback { * the spec did not change */ public boolean reset(boolean animate) { - synchronized (mLock) { - return resetLocked(animate); - } - } - private boolean resetLocked(boolean animate) { - if (!mRegistered) { - return false; - } - final MagnificationSpec spec = mCurrentMagnificationSpec; - final boolean changed = !spec.isNop(); - if (changed) { - spec.clear(); - onMagnificationChangedLocked(); - } - mIdOfLastServiceToMagnify = INVALID_ID; - sendSpecToAnimation(spec, animate); - return changed; + return mDisplay.reset(animate); + } /** @@ -435,30 +796,8 @@ public class MagnificationController implements Handler.Callback { * the spec did not change */ public boolean setScale(float scale, float pivotX, float pivotY, boolean animate, int id) { - synchronized (mLock) { - if (!mRegistered) { - return false; - } - // Constrain scale immediately for use in the pivot calculations. - scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); - - final Rect viewport = mTempRect; - mMagnificationRegion.getBounds(viewport); - final MagnificationSpec spec = mCurrentMagnificationSpec; - final float oldScale = spec.scale; - final float oldCenterX - = (viewport.width() / 2.0f - spec.offsetX + viewport.left) / oldScale; - final float oldCenterY - = (viewport.height() / 2.0f - spec.offsetY + viewport.top) / oldScale; - final float normPivotX = (pivotX - spec.offsetX) / oldScale; - final float normPivotY = (pivotY - spec.offsetY) / oldScale; - final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale); - final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale); - final float centerX = normPivotX + offsetX; - final float centerY = normPivotY + offsetY; - mIdOfLastServiceToMagnify = id; - return setScaleAndCenterLocked(scale, centerX, centerY, animate, id); - } + return mDisplay. + setScale(scale, pivotX, pivotY, animate, id); } /** @@ -471,17 +810,13 @@ public class MagnificationController implements Handler.Callback { * center * @param animate {@code true} to animate the transition, {@code false} * to transition immediately - * @param id the ID of the service requesting the change + * @param id the ID of the service requesting the change * @return {@code true} if the magnification spec changed, {@code false} if - * the spec did not change + * the spec did not change */ public boolean setCenter(float centerX, float centerY, boolean animate, int id) { - synchronized (mLock) { - if (!mRegistered) { - return false; - } - return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate, id); - } + return mDisplay. + setScaleAndCenter(Float.NaN, centerX, centerY, animate, id); } /** @@ -502,28 +837,8 @@ public class MagnificationController implements Handler.Callback { */ public boolean setScaleAndCenter( float scale, float centerX, float centerY, boolean animate, int id) { - synchronized (mLock) { - if (!mRegistered) { - return false; - } - return setScaleAndCenterLocked(scale, centerX, centerY, animate, id); - } - } - - private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY, - boolean animate, int id) { - if (DEBUG) { - Slog.i(LOG_TAG, - "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX - + ", centerY = " + centerY + ", animate = " + animate + ", id = " + id - + ")"); - } - final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY); - sendSpecToAnimation(mCurrentMagnificationSpec, animate); - if (isMagnifying() && (id != INVALID_ID)) { - mIdOfLastServiceToMagnify = id; - } - return changed; + return mDisplay. + setScaleAndCenter(scale, centerX, centerY, animate, id); } /** @@ -531,27 +846,14 @@ public class MagnificationController implements Handler.Callback { * opposite direction as the offsets passed in here. * * @param offsetX the amount in pixels to offset the region in the X direction, in current - * screen pixels. + * screen pixels. * @param offsetY the amount in pixels to offset the region in the Y direction, in current - * screen pixels. - * @param id the ID of the service requesting the change + * screen pixels. + * @param id the ID of the service requesting the change */ public void offsetMagnifiedRegion(float offsetX, float offsetY, int id) { - synchronized (mLock) { - if (!mRegistered) { - return; - } - - final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX; - final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY; - if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) { - onMagnificationChangedLocked(); - } - if (id != INVALID_ID) { - mIdOfLastServiceToMagnify = id; - } - sendSpecToAnimation(mCurrentMagnificationSpec, false); - } + mDisplay.offsetMagnifiedRegion(offsetX, offsetY, + id); } /** @@ -560,28 +862,26 @@ public class MagnificationController implements Handler.Callback { * @return The id */ public int getIdOfLastServiceToMagnify() { - return mIdOfLastServiceToMagnify; - } - - private void onMagnificationChangedLocked() { - mAms.notifyMagnificationChanged(mMagnificationRegion, - getScale(), getCenterX(), getCenterY()); - if (mUnregisterPending && !isMagnifying()) { - unregisterInternalLocked(); - } + return mDisplay.getIdOfLastServiceToMagnify(); } /** * Persists the current magnification scale to the current user's settings. */ public void persistScale() { - final float scale = mCurrentMagnificationSpec.scale; + persistScale(Display.DEFAULT_DISPLAY); + } + /** + * Persists the current magnification scale to the current user's settings. + */ + public void persistScale(int displayId) { + final float scale = mDisplay.getScale(); final int userId = mUserId; new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { - mSettingsBridge.putMagnificationScale(scale, userId); + mSettingsBridge.putMagnificationScale(scale, displayId, userId); return null; } }.execute(); @@ -595,98 +895,7 @@ public class MagnificationController implements Handler.Callback { * scale if none is available */ public float getPersistedScale() { - return mSettingsBridge.getMagnificationScale(mUserId); - } - - /** - * Updates the current magnification spec. - * - * @param scale the magnification scale - * @param centerX the unscaled, screen-relative X coordinate of the center - * of the viewport, or {@link Float#NaN} to leave unchanged - * @param centerY the unscaled, screen-relative Y coordinate of the center - * of the viewport, or {@link Float#NaN} to leave unchanged - * @return {@code true} if the magnification spec changed or {@code false} - * otherwise - */ - private boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY) { - // Handle defaults. - if (Float.isNaN(centerX)) { - centerX = getCenterX(); - } - if (Float.isNaN(centerY)) { - centerY = getCenterY(); - } - if (Float.isNaN(scale)) { - scale = getScale(); - } - - // Compute changes. - boolean changed = false; - - final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); - if (Float.compare(mCurrentMagnificationSpec.scale, normScale) != 0) { - mCurrentMagnificationSpec.scale = normScale; - changed = true; - } - - final float nonNormOffsetX = mMagnificationBounds.width() / 2.0f - + mMagnificationBounds.left - centerX * normScale; - final float nonNormOffsetY = mMagnificationBounds.height() / 2.0f - + mMagnificationBounds.top - centerY * normScale; - changed |= updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY); - - if (changed) { - onMagnificationChangedLocked(); - } - - return changed; - } - - private boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) { - if (DEBUG) { - Slog.i(LOG_TAG, - "updateCurrentSpecWithOffsetsLocked(nonNormOffsetX = " + nonNormOffsetX - + ", nonNormOffsetY = " + nonNormOffsetY + ")"); - } - boolean changed = false; - final float offsetX = MathUtils.constrain( - nonNormOffsetX, getMinOffsetXLocked(), getMaxOffsetXLocked()); - if (Float.compare(mCurrentMagnificationSpec.offsetX, offsetX) != 0) { - mCurrentMagnificationSpec.offsetX = offsetX; - changed = true; - } - final float offsetY = MathUtils.constrain( - nonNormOffsetY, getMinOffsetYLocked(), getMaxOffsetYLocked()); - if (Float.compare(mCurrentMagnificationSpec.offsetY, offsetY) != 0) { - mCurrentMagnificationSpec.offsetY = offsetY; - changed = true; - } - return changed; - } - - private float getMinOffsetXLocked() { - final float viewportWidth = mMagnificationBounds.width(); - final float viewportLeft = mMagnificationBounds.left; - return (viewportLeft + viewportWidth) - - (viewportLeft + viewportWidth) * mCurrentMagnificationSpec.scale; - } - - private float getMaxOffsetXLocked() { - return mMagnificationBounds.left - - mMagnificationBounds.left * mCurrentMagnificationSpec.scale; - } - - private float getMinOffsetYLocked() { - final float viewportHeight = mMagnificationBounds.height(); - final float viewportTop = mMagnificationBounds.top; - return (viewportTop + viewportHeight) - - (viewportTop + viewportHeight) * mCurrentMagnificationSpec.scale; - } - - private float getMaxOffsetYLocked() { - return mMagnificationBounds.top - - mMagnificationBounds.top * mCurrentMagnificationSpec.scale; + return mSettingsBridge.getMagnificationScale(Display.DEFAULT_DISPLAY, mUserId); } /** @@ -706,20 +915,14 @@ public class MagnificationController implements Handler.Callback { } } - /** + /** * Resets magnification if magnification and auto-update are both enabled. * * @param animate whether the animate the transition * @return whether was {@link #isMagnifying magnifying} */ - boolean resetIfNeeded(boolean animate) { - synchronized (mLock) { - if (isMagnifying()) { - reset(animate); - return true; - } - return false; - } + public boolean resetIfNeeded(boolean animate) { + return mDisplay.resetIfNeeded(animate); } /** @@ -728,132 +931,23 @@ public class MagnificationController implements Handler.Callback { * @param connectionId the connection ID be disabled. * @return {@code true} on success, {@code false} on failure */ - boolean resetIfNeeded(int connectionId) { - if (mIdOfLastServiceToMagnify == connectionId) { - return resetIfNeeded(true /*animate*/); - } - return false; + public boolean resetIfNeeded(int connectionId) { + return mDisplay.resetIfNeeded(connectionId); } void setForceShowMagnifiableBounds(boolean show) { - if (mRegistered) { - mWindowManager.setForceShowMagnifiableBounds(show); - } - } - - private void getMagnifiedFrameInContentCoordsLocked(Rect outFrame) { - final float scale = getSentScale(); - final float offsetX = getSentOffsetX(); - final float offsetY = getSentOffsetY(); - getMagnificationBounds(outFrame); - outFrame.offset((int) -offsetX, (int) -offsetY); - outFrame.scale(1.0f / scale); - } - - private void requestRectangleOnScreen(int left, int top, int right, int bottom) { - synchronized (mLock) { - final Rect magnifiedFrame = mTempRect; - getMagnificationBounds(magnifiedFrame); - if (!magnifiedFrame.intersects(left, top, right, bottom)) { - return; - } - - final Rect magnifFrameInScreenCoords = mTempRect1; - getMagnifiedFrameInContentCoordsLocked(magnifFrameInScreenCoords); - - final float scrollX; - final float scrollY; - if (right - left > magnifFrameInScreenCoords.width()) { - final int direction = TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault()); - if (direction == View.LAYOUT_DIRECTION_LTR) { - scrollX = left - magnifFrameInScreenCoords.left; - } else { - scrollX = right - magnifFrameInScreenCoords.right; - } - } else if (left < magnifFrameInScreenCoords.left) { - scrollX = left - magnifFrameInScreenCoords.left; - } else if (right > magnifFrameInScreenCoords.right) { - scrollX = right - magnifFrameInScreenCoords.right; - } else { - scrollX = 0; - } - - if (bottom - top > magnifFrameInScreenCoords.height()) { - scrollY = top - magnifFrameInScreenCoords.top; - } else if (top < magnifFrameInScreenCoords.top) { - scrollY = top - magnifFrameInScreenCoords.top; - } else if (bottom > magnifFrameInScreenCoords.bottom) { - scrollY = bottom - magnifFrameInScreenCoords.bottom; - } else { - scrollY = 0; - } - - final float scale = getScale(); - offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_ID); - } - } - - private void sendSpecToAnimation(MagnificationSpec spec, boolean animate) { - if (DEBUG) { - Slog.i(LOG_TAG, "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")"); - } - if (Thread.currentThread().getId() == mMainThreadId) { - mSpecAnimationBridge.updateSentSpecMainThread(spec, animate); - } else { - mHandler.obtainMessage(MSG_SEND_SPEC_TO_ANIMATION, - animate ? 1 : 0, 0, spec).sendToTarget(); - } + mDisplay.setForceShowMagnifiableBounds(show); } private void onScreenTurnedOff() { - mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF); - } - - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_SEND_SPEC_TO_ANIMATION: - final boolean animate = msg.arg1 == 1; - final MagnificationSpec spec = (MagnificationSpec) msg.obj; - mSpecAnimationBridge.updateSentSpecMainThread(spec, animate); - break; - case MSG_SCREEN_TURNED_OFF: - resetIfNeeded(false); - break; - case MSG_ON_MAGNIFIED_BOUNDS_CHANGED: { - final SomeArgs args = (SomeArgs) msg.obj; - final Region magnifiedBounds = (Region) args.arg1; - onMagnificationRegionChanged(magnifiedBounds); - magnifiedBounds.recycle(); - args.recycle(); - } break; - case MSG_ON_RECTANGLE_ON_SCREEN_REQUESTED: { - final SomeArgs args = (SomeArgs) msg.obj; - final int left = args.argi1; - final int top = args.argi2; - final int right = args.argi3; - final int bottom = args.argi4; - requestRectangleOnScreen(left, top, right, bottom); - args.recycle(); - } break; - case MSG_ON_USER_CONTEXT_CHANGED: - resetIfNeeded(true); - break; - } - return true; + final Message m = PooledLambda.obtainMessage( + mDisplay::resetIfNeeded, false); + mHandler.sendMessage(m); } @Override public String toString() { - return "MagnificationController{" + - "mCurrentMagnificationSpec=" + mCurrentMagnificationSpec + - ", mMagnificationRegion=" + mMagnificationRegion + - ", mMagnificationBounds=" + mMagnificationBounds + - ", mUserId=" + mUserId + - ", mIdOfLastServiceToMagnify=" + mIdOfLastServiceToMagnify + - ", mRegistered=" + mRegistered + - ", mUnregisterPending=" + mUnregisterPending + - '}'; + return mDisplay.toString(); } /** @@ -974,6 +1068,7 @@ public class MagnificationController implements Handler.Callback { private static class ScreenStateObserver extends BroadcastReceiver { private final Context mContext; private final MagnificationController mController; + private boolean mRegistered = false; public ScreenStateObserver(Context context, MagnificationController controller) { mContext = context; @@ -981,11 +1076,17 @@ public class MagnificationController implements Handler.Callback { } public void register() { - mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_SCREEN_OFF)); + if (!mRegistered) { + mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_SCREEN_OFF)); + mRegistered = true; + } } public void unregister() { - mContext.unregisterReceiver(this); + if (mRegistered) { + mContext.unregisterReceiver(this); + mRegistered = false; + } } @Override @@ -1002,14 +1103,17 @@ public class MagnificationController implements Handler.Callback { mContentResolver = contentResolver; } - public void putMagnificationScale(float value, int userId) { + public void putMagnificationScale(float value, int displayId, int userId) { Settings.Secure.putFloatForUser(mContentResolver, - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, value, userId); + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE + ( + Display.DEFAULT_DISPLAY == displayId ? "" : displayId), + value, userId); } - public float getMagnificationScale(int userId) { + public float getMagnificationScale(int displayId, int userId) { return Settings.Secure.getFloatForUser(mContentResolver, - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE + + (Display.DEFAULT_DISPLAY == displayId ? "" : displayId), DEFAULT_MAGNIFICATION_SCALE, userId); } } 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/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 7c67596d92b4..858dcedd03cc 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3150,10 +3150,10 @@ class StorageManagerService extends IStorageManager.Stub if (toSystem) { // Everything else goes into sandbox. - return device + "Android/sandbox/" + sandboxId.replace(':', '/') + "/" + devicePath; + return device + "Android/sandbox/" + sandboxId + "/" + devicePath; } else { // Does path belong to this sandbox? If so, leave sandbox. - final String sandboxPrefix = "Android/sandbox/" + sandboxId.replace(':', '/') + "/"; + final String sandboxPrefix = "Android/sandbox/" + sandboxId + "/"; if (devicePath.startsWith(sandboxPrefix)) { return device + devicePath.substring(sandboxPrefix.length()); } 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 d56b523f07aa..7a0a742bfae7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -22,8 +22,11 @@ import static android.Manifest.permission.FILTER_EVENTS; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.REMOVE_TASKS; +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; @@ -461,10 +464,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int BROADCAST_FG_TIMEOUT = 10*1000; static final int BROADCAST_BG_TIMEOUT = 60*1000; - // Disable hidden API checks for the newly started instrumentation. - // Must be kept in sync with Am. - private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0; - public static final int MY_PID = myPid(); static final String[] EMPTY_STRING_ARRAY = new String[0]; @@ -745,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 = new ActiveUids(this, true /* postChangesToAtm */); /** * 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 @@ -981,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 @@ -2703,7 +2700,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); @@ -2839,7 +2836,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) { @@ -2847,7 +2844,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; } } @@ -2923,8 +2920,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) { @@ -5142,7 +5138,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; } } @@ -5156,7 +5152,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(); } // ========================================================= @@ -5210,8 +5206,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; } @@ -7136,13 +7131,13 @@ public class ActivityManagerService extends IActivityManager.Stub final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, String abiOverride) { return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */, - abiOverride); + false /* mountExtStorageFull */, abiOverride); } // TODO: Move to ProcessList? @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, - boolean disableHiddenApiChecks, String abiOverride) { + boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, @@ -7175,7 +7170,7 @@ public class ActivityManagerService extends IActivityManager.Stub mPersistentStartingProcesses.add(app); mProcessList.startProcessLocked(app, "added application", customProcess != null ? customProcess : app.processName, disableHiddenApiChecks, - abiOverride); + mountExtStorageFull, abiOverride); } return app; @@ -7619,7 +7614,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; } } @@ -9568,7 +9563,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++) { @@ -14701,11 +14696,13 @@ public class ActivityManagerService extends IActivityManager.Stub activeInstr.mResultClass = className; boolean disableHiddenApiChecks = ai.usesNonSdkApi() - || (flags & INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0; + || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0; if (disableHiddenApiChecks) { enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS, "disable hidden API checks"); } + final boolean mountExtStorageFull = isCallerShell() + && (flags & INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL) != 0; final long origId = Binder.clearCallingIdentity(); // Instrumentation can kill and relaunch even persistent processes @@ -14718,7 +14715,7 @@ public class ActivityManagerService extends IActivityManager.Stub } ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, - abiOverride); + mountExtStorageFull, abiOverride); app.setActiveInstrumentation(activeInstr); activeInstr.mFinished = false; activeInstr.mRunningProcesses.add(app); @@ -14731,6 +14728,11 @@ public class ActivityManagerService extends IActivityManager.Stub return true; } + private boolean isCallerShell() { + final int callingUid = Binder.getCallingUid(); + return callingUid == SHELL_UID || callingUid == ROOT_UID; + } + /** * Report errors that occur while attempting to start Instrumentation. Always writes the * error to the logs, but if somebody is watching, send the report there too. This enables @@ -16222,8 +16224,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 > @@ -16604,7 +16605,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 @@ -16793,8 +16794,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) { @@ -17229,8 +17229,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; @@ -17437,14 +17437,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)? @@ -17477,17 +17477,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); } @@ -17648,7 +17647,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); @@ -17712,8 +17711,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/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 692b2d433dbc..96601a20471b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -17,14 +17,13 @@ package com.android.server.am; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityTaskManager.RESIZE_MODE_USER; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; - import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; @@ -2902,6 +2901,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --receiver-permission <PERMISSION>: Require receiver to hold permission."); pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]"); pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]"); + pw.println(" [--no-isolated-storage]"); pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>"); pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the"); pw.println(" form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there"); @@ -2920,6 +2920,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;"); pw.println(" current user if not specified."); pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API."); + pw.println(" --no-isolated-storage: don't use isolated storage sandbox and "); + pw.println(" mount full external storage"); pw.println(" --no-window-animation: turn off window animations while running."); pw.println(" --abi <ABI>: Launch the instrumented process with the selected ABI."); pw.println(" This assumes that the process supports the selected ABI."); 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 3f172cc11468..805b979b4bb7 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -18,7 +18,6 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; import static android.app.ActivityThread.PROC_START_SEQ_IDENT; -import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; import static android.os.Process.FIRST_ISOLATED_UID; import static android.os.Process.LAST_ISOLATED_UID; @@ -28,6 +27,7 @@ import static android.os.Process.getFreeMemory; import static android.os.Process.getTotalMemory; import static android.os.Process.killProcessQuiet; import static android.os.Process.startWebView; +import static android.os.storage.StorageManager.PROP_ISOLATED_STORAGE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; @@ -45,17 +45,6 @@ import static com.android.server.am.ActivityManagerService.TAG_PROCESSES; import static com.android.server.am.ActivityManagerService.TAG_PSS; import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; -import dalvik.system.VMRuntime; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppProtoEnums; @@ -64,11 +53,14 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.res.Resources; +import android.graphics.Point; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.FactoryTest; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -77,6 +69,17 @@ import android.os.Process; import android.os.RemoteException; import android.os.StrictMode; import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.Trace; +import android.os.UserHandle; +import android.os.storage.StorageManagerInternal; +import android.text.TextUtils; +import android.util.EventLog; +import android.util.LongSparseArray; +import android.util.Slog; +import android.util.SparseArray; +import android.util.StatsLog; +import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -91,21 +94,16 @@ import com.android.server.Watchdog; import com.android.server.pm.dex.DexManager; import com.android.server.wm.WindowManagerService; -import android.content.res.Resources; -import android.graphics.Point; -import android.os.SystemProperties; -import android.net.LocalSocketAddress; -import android.net.LocalSocket; -import android.os.Trace; -import android.os.UserHandle; -import android.os.storage.StorageManagerInternal; -import android.text.TextUtils; -import android.util.EventLog; -import android.util.LongSparseArray; -import android.util.Slog; -import android.util.SparseArray; -import android.util.StatsLog; -import android.view.Display; +import dalvik.system.VMRuntime; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Activity manager code dealing with processes. @@ -1182,7 +1180,8 @@ public final class ProcessList { */ @GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, String hostingType, - String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) { + String hostingNameStr, boolean disableHiddenApiChecks, boolean mountExtStorageFull, + String abiOverride) { if (app.pendingStart) { return true; } @@ -1224,10 +1223,15 @@ public final class ProcessList { final IPackageManager pm = AppGlobals.getPackageManager(); permGids = pm.getPackageGids(app.info.packageName, MATCH_DIRECT_BOOT_AUTO, app.userId); - StorageManagerInternal storageManagerInternal = LocalServices.getService( - StorageManagerInternal.class); - mountExternal = storageManagerInternal.getExternalStorageMountMode(uid, - app.info.packageName); + if (SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, false) + && mountExtStorageFull) { + mountExternal = Zygote.MOUNT_EXTERNAL_FULL; + } else { + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + mountExternal = storageManagerInternal.getExternalStorageMountMode(uid, + app.info.packageName); + } } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -1482,7 +1486,7 @@ public final class ProcessList { final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride) { return startProcessLocked(app, hostingType, hostingNameStr, - false /* disableHiddenApiChecks */, abiOverride); + false /* disableHiddenApiChecks */, false /* mountExtStorageFull */, abiOverride); } @GuardedBy("mService") @@ -1911,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); @@ -1923,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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1180af87ae34..9399ebf5b413 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9539,7 +9539,7 @@ public class PackageManagerService extends IPackageManager.Stub } } } - if (deleteSandboxData) { + if (deleteSandboxData && getStorageManagerInternal() != null) { getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId); } } catch (PackageManagerException e) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6a7e65400fa7..e2818b70deb1 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2634,6 +2634,10 @@ public final class Settings { writeKernelMappingLPr(ps); } + for (final SharedUserSetting sus : mSharedUsers.values()) { + knownSet.remove(sus.getSandboxName()); + } + // Remove any unclaimed mappings for (int i = 0; i < knownSet.size(); i++) { final String name = knownSet.valueAt(i); @@ -2644,30 +2648,42 @@ public final class Settings { } } + void writeKernelMappingLPr(SharedUserSetting sus) { + if (mKernelMappingFilename == null || sus == null || sus.name == null) return; + + writeKernelMappingLPr(sus.getSandboxName(), sus.userId, sus.getNotInstalledUserIds()); + } + void writeKernelMappingLPr(PackageSetting ps) { if (mKernelMappingFilename == null || ps == null || ps.name == null) return; - KernelPackageState cur = mKernelMapping.get(ps.name); + writeKernelMappingLPr(ps.name, ps.appId, ps.getNotInstalledUserIds()); + if (ps.sharedUser != null) { + writeKernelMappingLPr(ps.sharedUser); + } + } + + void writeKernelMappingLPr(String name, int appId, int[] excludedUserIds) { + KernelPackageState cur = mKernelMapping.get(name); final boolean firstTime = cur == null; - int[] excludedUserIds = ps.getNotInstalledUserIds(); final boolean userIdsChanged = firstTime || !Arrays.equals(excludedUserIds, cur.excludedUserIds); // Package directory - final File dir = new File(mKernelMappingFilename, ps.name); + final File dir = new File(mKernelMappingFilename, name); if (firstTime) { dir.mkdir(); // Create a new mapping state cur = new KernelPackageState(); - mKernelMapping.put(ps.name, cur); + mKernelMapping.put(name, cur); } // If mapping is incorrect or non-existent, write the appid file - if (cur.appId != ps.appId) { + if (cur.appId != appId) { final File appIdFile = new File(dir, "appid"); - writeIntToFile(appIdFile, ps.appId); - if (DEBUG_KERNEL) Slog.d(TAG, "Mapping " + ps.name + " to " + ps.appId); + writeIntToFile(appIdFile, appId); + if (DEBUG_KERNEL) Slog.d(TAG, "Mapping " + name + " to " + appId); } if (userIdsChanged) { @@ -2677,7 +2693,7 @@ public final class Settings { excludedUserIds[i])) { writeIntToFile(new File(dir, "excluded_userids"), excludedUserIds[i]); if (DEBUG_KERNEL) Slog.d(TAG, "Writing " + excludedUserIds[i] + " to " - + ps.name + "/excluded_userids"); + + name + "/excluded_userids"); } } // Build the inclusion list -- the ids to remove from the exclusion list @@ -2687,7 +2703,7 @@ public final class Settings { writeIntToFile(new File(dir, "clear_userid"), cur.excludedUserIds[i]); if (DEBUG_KERNEL) Slog.d(TAG, "Writing " + cur.excludedUserIds[i] + " to " - + ps.name + "/clear_userid"); + + name + "/clear_userid"); } } diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index 1a8b2af5a3a9..32826e51f0a4 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -23,6 +23,10 @@ import android.service.pm.PackageServiceDumpProto; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.ArrayUtils; + +import libcore.util.EmptyArray; + import java.util.ArrayList; import java.util.List; @@ -144,6 +148,28 @@ public final class SharedUserSetting extends SettingBase { } } + /** Returns userIds which doesn't have any packages with this sharedUserId */ + public int[] getNotInstalledUserIds() { + int[] excludedUserIds = null; + for (PackageSetting ps : packages) { + final int[] userIds = ps.getNotInstalledUserIds(); + if (excludedUserIds == null) { + excludedUserIds = userIds; + } else { + for (int userId : excludedUserIds) { + if (!ArrayUtils.contains(userIds, userId)) { + excludedUserIds = ArrayUtils.removeInt(excludedUserIds, userId); + } + } + } + } + return excludedUserIds == null ? EmptyArray.INT : excludedUserIds; + } + + public String getSandboxName() { + return "shared:" + name; + } + /** Updates all fields in this shared user setting from another. */ public SharedUserSetting updateFrom(SharedUserSetting sharedUser) { copyFrom(sharedUser); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index dae7b012b9b8..c5cee32f1596 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -6864,37 +6864,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int getUserRotationMode() { - return Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ? - WindowManagerPolicy.USER_ROTATION_FREE : - WindowManagerPolicy.USER_ROTATION_LOCKED; - } - - // User rotation: to be used when all else fails in assigning an orientation to the device - @Override - public void setUserRotationMode(int mode, int rot) { - ContentResolver res = mContext.getContentResolver(); - - // mUserRotationMode and mUserRotation will be assigned by the content observer - if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) { - Settings.System.putIntForUser(res, - Settings.System.USER_ROTATION, - rot, - UserHandle.USER_CURRENT); - Settings.System.putIntForUser(res, - Settings.System.ACCELEROMETER_ROTATION, - 0, - UserHandle.USER_CURRENT); - } else { - Settings.System.putIntForUser(res, - Settings.System.ACCELEROMETER_ROTATION, - 1, - UserHandle.USER_CURRENT); - } - } - - @Override public void setSafeMode(boolean safeMode) { mSafeMode = safeMode; if (safeMode) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 2a8e523f04c2..db13cbccf993 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -82,7 +82,6 @@ import android.view.IApplicationToken; import android.view.IWindowManager; import android.view.InputEventReceiver; import android.view.KeyEvent; -import android.view.Surface; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicyConstants; @@ -1483,26 +1482,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public void keepScreenOnStoppedLw(); /** - * Gets the current user rotation mode. - * - * @return The rotation mode. - * - * @see #USER_ROTATION_LOCKED - * @see #USER_ROTATION_FREE - */ - @UserRotationMode - public int getUserRotationMode(); - - /** - * Inform the policy that the user has chosen a preferred orientation ("rotation lock"). - * - * @param mode One of {@link #USER_ROTATION_LOCKED} or {@link #USER_ROTATION_FREE}. - * @param rotation One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90}, - * {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}. - */ - public void setUserRotationMode(@UserRotationMode int mode, @Surface.Rotation int rotation); - - /** * Called when a new system UI visibility is being reported, allowing * the policy to adjust what is actually reported. * @param visibility The raw visibility reported by the status bar. 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 93870e73ecab..c162afbf3e61 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -174,11 +174,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); private IWifiManager mWifiManager = null; private TelephonyManager mTelephony = null; - private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath()); - private final StatFs mStatFsSystem = - new StatFs(Environment.getRootDirectory().getAbsolutePath()); - private final StatFs mStatFsTemp = - new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); @GuardedBy("sStatsdLock") private final HashSet<Long> mDeathTimeMillis = new HashSet<>(); @GuardedBy("sStatsdLock") @@ -772,7 +767,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullBluetoothBytesTransfer( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = pullBluetoothData(); + BluetoothActivityEnergyInfo info = fetchBluetoothData(); if (info.getUidTraffic() != null) { for (UidTraffic traffic : info.getUidTraffic()) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, @@ -884,9 +879,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { long token = Binder.clearCallingIdentity(); - if (mWifiManager == null) { - mWifiManager = - IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE)); + synchronized (this) { + if (mWifiManager == null) { + mWifiManager = + IWifiManager.Stub.asInterface( + ServiceManager.getService(Context.WIFI_SERVICE)); + } } if (mWifiManager != null) { try { @@ -916,8 +914,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { long token = Binder.clearCallingIdentity(); - if (mTelephony == null) { - mTelephony = TelephonyManager.from(mContext); + synchronized (this) { + if (mTelephony == null) { + mTelephony = TelephonyManager.from(mContext); + } } if (mTelephony != null) { SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); @@ -941,7 +941,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullBluetoothActivityInfo( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = pullBluetoothData(); + BluetoothActivityEnergyInfo info = fetchBluetoothData(); StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeLong(info.getTimeStamp()); e.writeInt(info.getBluetoothStackState()); @@ -952,7 +952,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } - private synchronized BluetoothActivityEnergyInfo pullBluetoothData() { + private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( @@ -1323,30 +1323,35 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullProcessStats(int section, int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { - try { - long lastHighWaterMark = readProcStatsHighWaterMark(section); - List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); - long highWaterMark = mProcessStats.getCommittedStats( - lastHighWaterMark, section, true, statsFiles); - if (statsFiles.size() != 1) { - return; + synchronized (this) { + try { + long lastHighWaterMark = readProcStatsHighWaterMark(section); + List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); + long highWaterMark = mProcessStats.getCommittedStats( + lastHighWaterMark, section, true, statsFiles); + if (statsFiles.size() != 1) { + return; + } + InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream( + statsFiles.get(0)); + int[] len = new int[1]; + byte[] stats = readFully(stream, len); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, + wallClockNanos); + e.writeStorage(Arrays.copyOf(stats, len[0])); + pulledData.add(e); + new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + + lastHighWaterMark).delete(); + new File( + mBaseDir.getAbsolutePath() + "/" + section + "_" + + highWaterMark).createNewFile(); + } catch (IOException e) { + Log.e(TAG, "Getting procstats failed: ", e); + } catch (RemoteException e) { + Log.e(TAG, "Getting procstats failed: ", e); + } catch (SecurityException e) { + Log.e(TAG, "Getting procstats failed: ", e); } - InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0)); - int[] len = new int[1]; - byte[] stats = readFully(stream, len); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeStorage(Arrays.copyOf(stats, len[0])); - pulledData.add(e); - new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark).delete(); - new File( - mBaseDir.getAbsolutePath() + "/" + section + "_" - + highWaterMark).createNewFile(); - } catch (IOException e) { - Log.e(TAG, "Getting procstats failed: ", e); - } catch (RemoteException e) { - Log.e(TAG, "Getting procstats failed: ", e); - } catch (SecurityException e) { - Log.e(TAG, "Getting procstats failed: ", e); } } 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/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index bd82553b804b..847cff9c6646 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -55,6 +55,7 @@ public class DisplayRotation { private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; private final WindowManagerService mService; + private final DisplayContent mDisplayContent; private final DisplayPolicy mDisplayPolicy; private final Context mContext; private final Object mLock; @@ -106,6 +107,7 @@ public class DisplayRotation { DisplayRotation(WindowManagerService service, DisplayContent displayContent, DisplayPolicy displayPolicy, Context context, Object lock) { mService = service; + mDisplayContent = displayContent; mDisplayPolicy = displayPolicy; mContext = context; mLock = lock; @@ -225,6 +227,70 @@ public class DisplayRotation { } } + void restoreUserRotation(int userRotationMode, int userRotation) { + if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE + && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) { + Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode + + " for " + mDisplayContent); + userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; + } + if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) { + Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation + + " for " + mDisplayContent); + userRotation = Surface.ROTATION_0; + } + mUserRotationMode = userRotationMode; + mUserRotation = userRotation; + } + + private void setUserRotation(int userRotationMode, int userRotation) { + if (isDefaultDisplay) { + // We'll be notified via settings listener, so we don't need to update internal values. + final ContentResolver res = mContext.getContentResolver(); + final int accelerometerRotation = + userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1; + Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION, + accelerometerRotation, UserHandle.USER_CURRENT); + Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation, + UserHandle.USER_CURRENT); + return; + } + + boolean changed = false; + if (mUserRotationMode != userRotationMode) { + mUserRotationMode = userRotationMode; + changed = true; + } + if (mUserRotation != userRotation) { + mUserRotation = userRotation; + changed = true; + } + mService.mDisplaySettings.setUserRotation(mDisplayContent, userRotationMode, userRotation); + if (changed) { + mService.updateRotation(true /* alwaysSendConfiguration */, + false /* forceRelayout */); + mService.mDisplaySettings.writeSettingsLocked(); + } + } + + void freezeRotation(int rotation) { + rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation; + setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation); + } + + void thawRotation() { + setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation); + } + + boolean isRotationFrozen() { + if (!isDefaultDisplay) { + return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED; + } + + return Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; + } + /** @return true if com.android.internal.R.bool#config_forceDefaultOrientation is true. */ boolean isDefaultOrientationForced() { return mForceDefaultOrientation; @@ -381,9 +447,6 @@ public class DisplayRotation { * @param orientation An orientation constant, such as * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. * @param lastRotation The most recently used rotation. - * @param defaultDisplay Flag indicating whether the rotation is computed for the default - * display. Currently for all non-default displays sensors, docking mode, - * rotation lock and other factors are ignored. * @return The surface rotation to use. */ int rotationForOrientation(int orientation, int lastRotation) { @@ -418,8 +481,8 @@ public class DisplayRotation { final int preferredRotation; if (!isDefaultDisplay) { // For secondary displays we ignore things like displays sensors, docking mode and - // rotation lock, and always prefer a default rotation. - preferredRotation = Surface.ROTATION_0; + // rotation lock, and always prefer user rotation. + preferredRotation = mUserRotation; } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) { // Ignore sensor when lid switch is open and rotation is forced. preferredRotation = mLidOpenRotation; diff --git a/services/core/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java index bbb690f6a34a..28dc008fda9b 100644 --- a/services/core/java/com/android/server/wm/DisplaySettings.java +++ b/services/core/java/com/android/server/wm/DisplaySettings.java @@ -20,20 +20,23 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.WindowConfiguration; -import android.content.Context; -import android.content.pm.PackageManager; import android.graphics.Rect; import android.os.Environment; -import android.provider.Settings; import android.util.AtomicFile; import android.util.Slog; import android.util.Xml; import android.view.Display; import android.view.DisplayInfo; +import android.view.Surface; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; +import com.android.server.policy.WindowManagerPolicy; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.FileInputStream; @@ -43,10 +46,6 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashMap; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - /** * Current persistent settings about a display */ @@ -58,15 +57,25 @@ class DisplaySettings { private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>(); private static class Entry { - private final String name; - private int overscanLeft; - private int overscanTop; - private int overscanRight; - private int overscanBottom; - private int windowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED; + private final String mName; + private int mOverscanLeft; + private int mOverscanTop; + private int mOverscanRight; + private int mOverscanBottom; + private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED; + private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; + private int mUserRotation = Surface.ROTATION_0; private Entry(String _name) { - name = _name; + mName = _name; + } + + private boolean isEmpty() { + return mOverscanLeft == 0 && mOverscanTop == 0 && mOverscanRight == 0 + && mOverscanBottom == 0 + && mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED + && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE + && mUserRotation == Surface.ROTATION_0; } } @@ -90,13 +99,30 @@ class DisplaySettings { return entry; } + private Entry getOrCreateEntry(String uniqueId, String name) { + Entry entry = getEntry(uniqueId, name); + if (entry == null) { + entry = new Entry(uniqueId); + mEntries.put(uniqueId, entry); + } + return entry; + } + + private void removeEntryIfEmpty(String uniqueId, String name) { + final Entry entry = getEntry(uniqueId, name); + if (entry.isEmpty()) { + mEntries.remove(uniqueId); + mEntries.remove(name); + } + } + private void getOverscanLocked(String name, String uniqueId, Rect outRect) { final Entry entry = getEntry(name, uniqueId); if (entry != null) { - outRect.left = entry.overscanLeft; - outRect.top = entry.overscanTop; - outRect.right = entry.overscanRight; - outRect.bottom = entry.overscanBottom; + outRect.left = entry.mOverscanLeft; + outRect.top = entry.mOverscanTop; + outRect.right = entry.mOverscanRight; + outRect.bottom = entry.mOverscanBottom; } else { outRect.set(0, 0, 0, 0); } @@ -104,28 +130,22 @@ class DisplaySettings { void setOverscanLocked(String uniqueId, String name, int left, int top, int right, int bottom) { - if (left == 0 && top == 0 && right == 0 && bottom == 0) { - // Right now all we are storing is overscan; if there is no overscan, - // we have no need for the entry. - mEntries.remove(uniqueId); - // Legacy name might have been in used, so we need to clear it. - mEntries.remove(name); - return; - } Entry entry = mEntries.get(uniqueId); - if (entry == null) { - entry = new Entry(uniqueId); - mEntries.put(uniqueId, entry); + if (left == 0 && top == 0 && right == 0 && bottom == 0 && entry == null) { + // All default value, no action needed. + return; } - entry.overscanLeft = left; - entry.overscanTop = top; - entry.overscanRight = right; - entry.overscanBottom = bottom; + entry = getOrCreateEntry(uniqueId, name); + entry.mOverscanLeft = left; + entry.mOverscanTop = top; + entry.mOverscanRight = right; + entry.mOverscanBottom = bottom; + removeEntryIfEmpty(uniqueId, name); } private int getWindowingModeLocked(String name, String uniqueId, int displayId) { final Entry entry = getEntry(name, uniqueId); - int windowingMode = entry != null ? entry.windowingMode + int windowingMode = entry != null ? entry.mWindowingMode : WindowConfiguration.WINDOWING_MODE_UNDEFINED; // This display used to be in freeform, but we don't support freeform anymore, so fall // back to fullscreen. @@ -148,6 +168,36 @@ class DisplaySettings { return windowingMode; } + void setUserRotation(DisplayContent dc, int rotationMode, int rotation) { + final DisplayInfo displayInfo = dc.getDisplayInfo(); + + final String uniqueId = displayInfo.uniqueId; + final String name = displayInfo.name; + Entry entry = getEntry(displayInfo.name, uniqueId); + if (rotationMode == WindowManagerPolicy.USER_ROTATION_FREE + && rotation == Surface.ROTATION_0 && entry == null) { + // All default values. No action needed. + return; + } + + entry = getOrCreateEntry(uniqueId, name); + entry.mUserRotationMode = rotationMode; + entry.mUserRotation = rotation; + removeEntryIfEmpty(uniqueId, name); + } + + private void restoreUserRotation(DisplayContent dc) { + final DisplayInfo info = dc.getDisplayInfo(); + + final Entry entry = getEntry(info.name, info.uniqueId); + final int userRotationMode = entry != null ? entry.mUserRotationMode + : WindowManagerPolicy.USER_ROTATION_FREE; + final int userRotation = entry != null ? entry.mUserRotation + : Surface.ROTATION_0; + + dc.getDisplayRotation().restoreUserRotation(userRotationMode, userRotation); + } + void applySettingsToDisplayLocked(DisplayContent dc) { final DisplayInfo displayInfo = dc.getDisplayInfo(); @@ -161,6 +211,8 @@ class DisplaySettings { displayInfo.overscanTop = rect.top; displayInfo.overscanRight = rect.right; displayInfo.overscanBottom = rect.bottom; + + restoreUserRotation(dc); } void readSettingsLocked() { @@ -244,12 +296,16 @@ class DisplaySettings { String name = parser.getAttributeValue(null, "name"); if (name != null) { Entry entry = new Entry(name); - entry.overscanLeft = getIntAttribute(parser, "overscanLeft"); - entry.overscanTop = getIntAttribute(parser, "overscanTop"); - entry.overscanRight = getIntAttribute(parser, "overscanRight"); - entry.overscanBottom = getIntAttribute(parser, "overscanBottom"); - entry.windowingMode = getIntAttribute(parser, "windowingMode", + entry.mOverscanLeft = getIntAttribute(parser, "overscanLeft"); + entry.mOverscanTop = getIntAttribute(parser, "overscanTop"); + entry.mOverscanRight = getIntAttribute(parser, "overscanRight"); + entry.mOverscanBottom = getIntAttribute(parser, "overscanBottom"); + entry.mWindowingMode = getIntAttribute(parser, "windowingMode", WindowConfiguration.WINDOWING_MODE_UNDEFINED); + entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode", + WindowManagerPolicy.USER_ROTATION_FREE); + entry.mUserRotation = getIntAttribute(parser, "userRotation", + Surface.ROTATION_0); mEntries.put(name, entry); } XmlUtils.skipCurrentTag(parser); @@ -272,21 +328,28 @@ class DisplaySettings { for (Entry entry : mEntries.values()) { out.startTag(null, "display"); - out.attribute(null, "name", entry.name); - if (entry.overscanLeft != 0) { - out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft)); + out.attribute(null, "name", entry.mName); + if (entry.mOverscanLeft != 0) { + out.attribute(null, "overscanLeft", Integer.toString(entry.mOverscanLeft)); + } + if (entry.mOverscanTop != 0) { + out.attribute(null, "overscanTop", Integer.toString(entry.mOverscanTop)); + } + if (entry.mOverscanRight != 0) { + out.attribute(null, "overscanRight", Integer.toString(entry.mOverscanRight)); } - if (entry.overscanTop != 0) { - out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop)); + if (entry.mOverscanBottom != 0) { + out.attribute(null, "overscanBottom", Integer.toString(entry.mOverscanBottom)); } - if (entry.overscanRight != 0) { - out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight)); + if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) { + out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode)); } - if (entry.overscanBottom != 0) { - out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom)); + if (entry.mUserRotationMode != WindowManagerPolicy.USER_ROTATION_FREE) { + out.attribute(null, "userRotationMode", + Integer.toString(entry.mUserRotationMode)); } - if (entry.windowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) { - out.attribute(null, "windowingMode", Integer.toString(entry.windowingMode)); + if (entry.mUserRotation != Surface.ROTATION_0) { + out.attribute(null, "userRotation", Integer.toString(entry.mUserRotation)); } out.endTag(null, "display"); } 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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 056e92e3b654..5642b1f91700 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3668,14 +3668,19 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void freezeRotation(int rotation) { + freezeDisplayRotation(Display.DEFAULT_DISPLAY, rotation); + } + /** * Freeze rotation changes. (Enable "rotation lock".) * Persists across reboots. - * @param rotation The desired rotation to freeze to, or -1 to use the - * current rotation. + * @param displayId The ID of the display to freeze. + * @param rotation The desired rotation to freeze to, or -1 to use the current rotation. */ @Override - public void freezeRotation(int rotation) { + public void freezeDisplayRotation(int displayId, int rotation) { // TODO(multi-display): Track which display is rotated. if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "freezeRotation()")) { @@ -3686,14 +3691,16 @@ public class WindowManagerService extends IWindowManager.Stub + "rotation constant."); } - final int defaultDisplayRotation = getDefaultDisplayRotation(); - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "freezeRotation: mRotation=" - + defaultDisplayRotation); - long origId = Binder.clearCallingIdentity(); try { - mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, - rotation == -1 ? defaultDisplayRotation : rotation); + synchronized (mWindowMap) { + final DisplayContent display = mRoot.getDisplayContent(displayId); + if (display == null) { + Slog.w(TAG, "Trying to freeze rotation for a missing display."); + return; + } + display.getDisplayRotation().freezeRotation(rotation); + } } finally { Binder.restoreCallingIdentity(origId); } @@ -3701,12 +3708,17 @@ public class WindowManagerService extends IWindowManager.Stub updateRotationUnchecked(false, false); } + @Override + public void thawRotation() { + thawDisplayRotation(Display.DEFAULT_DISPLAY); + } + /** * Thaw rotation changes. (Disable "rotation lock".) * Persists across reboots. */ @Override - public void thawRotation() { + public void thawDisplayRotation(int displayId) { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "thawRotation()")) { throw new SecurityException("Requires SET_ORIENTATION permission"); @@ -3717,8 +3729,14 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { - mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, - 777); // rot not used + synchronized (mWindowMap) { + final DisplayContent display = mRoot.getDisplayContent(displayId); + if (display == null) { + Slog.w(TAG, "Trying to thaw rotation for a missing display."); + return; + } + display.getDisplayRotation().thawRotation(); + } } finally { Binder.restoreCallingIdentity(origId); } @@ -3726,6 +3744,23 @@ public class WindowManagerService extends IWindowManager.Stub updateRotationUnchecked(false, false); } + @Override + public boolean isRotationFrozen() { + return isDisplayRotationFrozen(Display.DEFAULT_DISPLAY); + } + + @Override + public boolean isDisplayRotationFrozen(int displayId) { + synchronized (mWindowMap) { + final DisplayContent display = mRoot.getDisplayContent(displayId); + if (display == null) { + Slog.w(TAG, "Trying to thaw rotation for a missing display."); + return false; + } + return display.getDisplayRotation().isRotationFrozen(); + } + } + /** * Recalculate the current rotation. * @@ -3795,11 +3830,6 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean isRotationFrozen() { - return mPolicy.getUserRotationMode() == WindowManagerPolicy.USER_ROTATION_LOCKED; - } - - @Override public int watchRotation(IRotationWatcher watcher, int displayId) { final DisplayContent displayContent; synchronized (mWindowMap) { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 831418b4b2b4..bf2d0df2bec3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -26,6 +26,7 @@ import android.os.UserHandle; import android.util.DisplayMetrics; import android.view.Display; import android.view.IWindowManager; +import android.view.Surface; import java.io.PrintWriter; import java.util.regex.Matcher; @@ -73,6 +74,8 @@ public class WindowManagerShellCommand extends ShellCommand { // trace files can be written. return mInternal.mWindowTracing.onShellCommand(this, getNextArgRequired()); + case "set-user-rotation": + return runSetDisplayUserRotation(pw); default: return handleDefaultCommands(cmd); } @@ -262,6 +265,36 @@ public class WindowManagerShellCommand extends ShellCommand { return Integer.parseInt(s); } + private int runSetDisplayUserRotation(PrintWriter pw) { + final String lockMode = getNextArgRequired(); + + int displayId = Display.DEFAULT_DISPLAY; + String arg = getNextArg(); + if ("-d".equals(arg)) { + displayId = Integer.parseInt(getNextArgRequired()); + arg = getNextArg(); + } + + if ("free".equals(lockMode)) { + mInternal.thawDisplayRotation(displayId); + return 0; + } + + if (!lockMode.equals("lock")) { + getErrPrintWriter().println("Error: lock mode needs to be either free or lock."); + return -1; + } + + try { + final int rotation = arg != null ? Integer.parseInt(arg) : Surface.ROTATION_0; + mInternal.freezeDisplayRotation(displayId, rotation); + return 0; + } catch (IllegalArgumentException e) { + getErrPrintWriter().println("Error: " + e.getMessage()); + return -1; + } + } + @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); @@ -279,6 +312,8 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Set display scaling mode."); pw.println(" dismiss-keyguard"); pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); + pw.println(" set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]"); + pw.println(" Set user rotation mode and user rotation."); if (!IS_USER) { pw.println(" tracing (start | stop)"); pw.println(" Start or stop window tracing."); 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 b83a79fc232c..e6cbb5badb9e 100644 --- a/services/tests/mockingservicestests/Android.mk +++ b/services/tests/mockingservicestests/Android.mk @@ -23,7 +23,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ frameworks-base-testutils \ services.core \ services.net \ - androidx-test \ + androidx.test.runner \ mockito-target-extended-minus-junit4 \ platform-test-annotations \ ShortcutManagerTestUtils \ 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/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 2957267d2e5b..878179bb251d 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -24,7 +24,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ services.net \ services.usage \ guava \ - androidx-test \ + androidx.test.runner \ + androidx.test.rules \ mockito-target-minus-junit4 \ platform-test-annotations \ ShortcutManagerTestUtils \ diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java index 43438b99edef..802253280614 100644 --- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java @@ -124,7 +124,7 @@ public class StorageManagerServiceTest { "/storage/emulated/0/Android/sandbox/com.grey/foo.jpg", "/storage/emulated/0/foo.jpg", PKG_GREY); assertTranslation( - "/storage/emulated/0/Android/sandbox/shared/colors/foo.jpg", + "/storage/emulated/0/Android/sandbox/shared:colors/foo.jpg", "/storage/emulated/0/foo.jpg", PKG_RED); } @@ -134,7 +134,7 @@ public class StorageManagerServiceTest { "/storage/0000-0000/Android/sandbox/com.grey/foo/bar.jpg", "/storage/0000-0000/foo/bar.jpg", PKG_GREY); assertTranslation( - "/storage/0000-0000/Android/sandbox/shared/colors/foo/bar.jpg", + "/storage/0000-0000/Android/sandbox/shared:colors/foo/bar.jpg", "/storage/0000-0000/foo/bar.jpg", PKG_RED); } @@ -147,7 +147,7 @@ public class StorageManagerServiceTest { // Accessing other package paths goes into sandbox assertTranslation( - "/storage/emulated/0/Android/sandbox/shared/colors/" + "/storage/emulated/0/Android/sandbox/shared:colors/" + "Android/data/com.grey/foo.jpg", "/storage/emulated/0/Android/data/com.grey/foo.jpg", PKG_RED); } @@ -192,7 +192,7 @@ public class StorageManagerServiceTest { // Sandboxes can't see paths in other sandboxes try { mService.translateSystemToApp( - "/storage/emulated/0/Android/sandbox/shared/colors/foo.jpg", + "/storage/emulated/0/Android/sandbox/shared:colors/foo.jpg", PKG_GREY, UserHandle.USER_SYSTEM); fail(); } catch (SecurityException expected) { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java index c88b87328809..feffeef3f044 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java @@ -86,12 +86,8 @@ public class MagnificationControllerTest { final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class); final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class); final MessageCapturingHandler mMessageCapturingHandler = - new MessageCapturingHandler(new Handler.Callback() { - @Override - public boolean handleMessage(Message msg) { - return mMagnificationController.handleMessage(msg); - } - }); + new MessageCapturingHandler(null); + final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class); MagnificationController.SettingsBridge mMockSettingsBridge; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java index 79e4d705db19..032074a7e398 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java @@ -29,9 +29,11 @@ import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.animation.ValueAnimator; import android.annotation.NonNull; import android.content.Context; import android.os.Message; @@ -44,7 +46,9 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.testutils.OffsettableClock; import com.android.server.testutils.TestHandler; +import com.android.server.wm.WindowManagerInternal; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -101,8 +105,15 @@ public class MagnificationGestureHandlerTest { public static final float DEFAULT_Y = 299; private Context mContext; - private AccessibilityManagerService mAms; - private MagnificationController mMagnificationController; + final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class); + final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class); + final MessageCapturingHandler mMessageCapturingHandler = + new MessageCapturingHandler(null); + final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class); + MagnificationController.SettingsBridge mMockSettingsBridge = + mock(MagnificationController.SettingsBridge.class); + MagnificationController mMagnificationController; + private OffsettableClock mClock; private MagnificationGestureHandler mMgh; private TestHandler mHandler; @@ -112,9 +123,9 @@ public class MagnificationGestureHandlerTest { @Before public void setUp() { mContext = InstrumentationRegistry.getContext(); - mAms = new AccessibilityManagerService(mContext); - mMagnificationController = new MagnificationController( - mContext, mAms, /* lock */ new Object()) { + mMagnificationController = new MagnificationController(mContext, mMockAms, new Object(), + mMessageCapturingHandler, mMockWindowManager, mMockValueAnimator, + mMockSettingsBridge) { @Override public boolean magnificationRegionContains(float x, float y) { return true; @@ -123,7 +134,7 @@ public class MagnificationGestureHandlerTest { @Override void setForceShowMagnifiableBounds(boolean show) {} }; - mMagnificationController.mRegistered = true; + mMagnificationController.register(); mClock = new OffsettableClock.Stopped(); boolean detectTripleTap = true; @@ -131,6 +142,11 @@ public class MagnificationGestureHandlerTest { mMgh = newInstance(detectTripleTap, detectShortcutTrigger); } + @After + public void tearDown() { + mMagnificationController.unregister(); + } + @NonNull private MagnificationGestureHandler newInstance(boolean detectTripleTap, boolean detectShortcutTrigger) { 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/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/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java index 07eafa5c4be4..a028d5eeb02e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java @@ -18,23 +18,34 @@ package com.android.server.wm; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import android.app.WindowConfiguration; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.DisplayInfo; +import android.view.Surface; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.policy.WindowManagerPolicy; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; +/** + * Tests for the {@link DisplaySettings} class. + * + * Build/Install/Run: + * atest FrameworksServicesTests:com.android.server.wm.DisplaySettingsTests + */ @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) @@ -155,6 +166,71 @@ public class DisplaySettingsTests extends WindowTestsBase { assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */); } + @Test + public void testDefaultToFreeUserRotation() { + mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); + + final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation(); + assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, rotation.getUserRotationMode()); + assertFalse(rotation.isRotationFrozen()); + } + + @Test + public void testDefaultTo0DegRotation() { + mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); + + assertEquals(Surface.ROTATION_0, mSecondaryDisplay.getDisplayRotation().getUserRotation()); + } + + @Test + public void testPersistUserRotationModeInSameInstance() { + mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED, + Surface.ROTATION_90); + + mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); + + final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation(); + assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode()); + assertTrue(rotation.isRotationFrozen()); + } + + @Test + public void testPersistUserRotationInSameInstance() { + mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED, + Surface.ROTATION_90); + + mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); + + assertEquals(Surface.ROTATION_90, mSecondaryDisplay.getDisplayRotation().getUserRotation()); + } + + @Test + public void testPersistUserRotationModeAcrossInstances() { + mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED, + Surface.ROTATION_270); + mTarget.writeSettingsLocked(); + + DisplaySettings target = new DisplaySettings(sWm, mTestFolder); + target.readSettingsLocked(); + + target.applySettingsToDisplayLocked(mSecondaryDisplay); + + final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation(); + assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode()); + assertTrue(rotation.isRotationFrozen()); + } + + @Test + public void testPersistUserRotationAcrossInstances() { + mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED, + Surface.ROTATION_270); + + mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); + + assertEquals(Surface.ROTATION_270, + mSecondaryDisplay.getDisplayRotation().getUserRotation()); + } + private static void assertOverscan(DisplayContent display, int left, int top, int right, int bottom) { final DisplayInfo info = display.getDisplayInfo(); diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 474e5b75e5d8..51595514624c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -432,17 +432,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int getUserRotationMode() { - return 0; - } - - @Override - public void setUserRotationMode(int mode, - int rotation) { - - } - - @Override public int adjustSystemUiVisibilityLw(int visibility) { return 0; } diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk index 7e7decfa8e3b..ab222b941e94 100644 --- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk +++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk @@ -20,7 +20,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_STATIC_JAVA_LIBRARIES := androidx-test ub-uiautomator +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.runner ub-uiautomator LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk index 0f8b18ab92cf..c095ae0dd2ff 100644 --- a/services/tests/wmtests/Android.mk +++ b/services/tests/wmtests/Android.mk @@ -14,7 +14,7 @@ LOCAL_SRC_FILES := \ $(call all-java-files-under, ../servicestests/utils) LOCAL_STATIC_JAVA_LIBRARIES := \ - androidx-test \ + androidx.test.runner \ mockito-target-minus-junit4 \ platform-test-annotations \ 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/tests/Internal/res/xml/livewallpaper.xml b/tests/Internal/res/xml/livewallpaper.xml index 6b5e84e8f9ad..36e7e4182c31 100644 --- a/tests/Internal/res/xml/livewallpaper.xml +++ b/tests/Internal/res/xml/livewallpaper.xml @@ -16,4 +16,5 @@ --> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" - android:supportsAmbientMode="true"/>
\ No newline at end of file + android:settingsSliceUri="content://com.android.internal.tests/slice" + android:supportsAmbientMode="true"/> diff --git a/tests/Internal/src/android/app/WallpaperInfoTest.java b/tests/Internal/src/android/app/WallpaperInfoTest.java index 98045ae98541..7f06f2cb7aeb 100644 --- a/tests/Internal/src/android/app/WallpaperInfoTest.java +++ b/tests/Internal/src/android/app/WallpaperInfoTest.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.net.Uri; import android.os.Parcel; import android.service.wallpaper.WallpaperService; import android.support.test.InstrumentationRegistry; @@ -64,5 +65,31 @@ public class WallpaperInfoTest { fromParcel.supportsAmbientMode()); parcel.recycle(); } + + @Test + public void testGetSettingsSliceUri() throws Exception { + Context context = InstrumentationRegistry.getTargetContext(); + + Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); + intent.setPackage("com.android.internal.tests"); + PackageManager pm = context.getPackageManager(); + List<ResolveInfo> result = pm.queryIntentServices(intent, PackageManager.GET_META_DATA); + assertEquals(1, result.size()); + ResolveInfo info = result.get(0); + WallpaperInfo wallpaperInfo = new WallpaperInfo(context, info); + + // This expected Uri must be the same as that in livewallpaper.xml + Uri expectedUri = Uri.parse("content://com.android.internal.tests/slice"); + Uri settingsUri = wallpaperInfo.getSettingsSliceUri(); + assertEquals("The loaded URI should equal to the string in livewallpaper.xml", + 0, expectedUri.compareTo(settingsUri)); + Parcel parcel = Parcel.obtain(); + wallpaperInfo.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + WallpaperInfo fromParcel = WallpaperInfo.CREATOR.createFromParcel(parcel); + assertEquals("settingsSliceUri should be restorable from parcelable", + 0, expectedUri.compareTo(fromParcel.getSettingsSliceUri())); + parcel.recycle(); + } } diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java index 6500428253f6..18cdf96c7131 100644 --- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java +++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java @@ -34,7 +34,7 @@ public class Cujs { // Do an explicit GC in the system server process as part of the test // case to reduce GC-related sources of noise. // SIGUSR1 = 10 is the magic signal to trigger the GC. - int pid = mDevice.getPidForProcess("system_server"); + int pid = mDevice.getProcessPid("system_server"); mDevice.executeShellCommand("kill -10 " + pid); // Invoke the Device Cujs instrumentation to run the cujs. diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java index 03503cec5fec..26146ca0ea6c 100644 --- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java +++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java @@ -19,9 +19,6 @@ package com.android.tests.sysmem.host; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; -import java.util.InputMismatchException; -import java.util.Scanner; - /** * Wrapper around ITestDevice exposing useful device functions. */ @@ -58,29 +55,15 @@ class Device { /** * Returns the pid for the process with the given name. */ - public int getPidForProcess(String name) throws TestException { - String psout = executeShellCommand("ps -A -o PID,CMD"); - Scanner sc = new Scanner(psout); + public int getProcessPid(String name) throws TestException { try { - // ps output is of the form: - // PID CMD - // 1 init - // 2 kthreadd - // ... - // 9693 ps - sc.nextLine(); - while (sc.hasNextLine()) { - int pid = sc.nextInt(); - String cmd = sc.next(); - - if (name.equals(cmd)) { - return pid; - } + String pid = mDevice.getProcessPid(name); + if (pid == null) { + throw new TestException("failed to get pid for " + name); } - } catch (InputMismatchException e) { - throw new TestException("unexpected ps output format: " + psout, e); + return Integer.parseInt(pid); + } catch (DeviceNotAvailableException e) { + throw new TestException(e); } - - throw new TestException("failed to get pid for process " + name); } } diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java index b408a81d8f93..b46e642b5e92 100644 --- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java +++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java @@ -79,7 +79,7 @@ class Metrics { // adb root access is required to get showmap mDevice.enableAdbRoot(); - int pid = mDevice.getPidForProcess("system_server"); + int pid = mDevice.getProcessPid("system_server"); // Read showmap for system server and add it as a test log String showmap = mDevice.executeShellCommand("showmap " + pid); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 59ba8e7a6177..9adbe67c1553 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -3754,6 +3754,13 @@ public class WifiManager { mCallback.onProvisioningFailure(status); }); } + + @Override + public void onProvisioningComplete() { + mHandler.post(() -> { + mCallback.onProvisioningComplete(); + }); + } } /** diff --git a/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl index c2cb16ab847c..a6bdd5b6bfff 100644 --- a/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl +++ b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl @@ -32,5 +32,10 @@ oneway interface IProvisioningCallback * Service to manager callback providing Provisioning status */ void onProvisioningStatus(int status); + + /** + * Service to manager callback providing completion of Provisioning/Remediation flow + */ + void onProvisioningComplete(); } diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java index 6076175ce9d1..4b76526cbb59 100644 --- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java +++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java @@ -108,6 +108,48 @@ public abstract class ProvisioningCallback { public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; /** + * The reason code for provisioning failure when there is no PPS MO. + * MO. + */ + public static final int OSU_FAILURE_NO_PPS_MO = 16; + + /** + * The reason code for provisioning failure when there is no AAAServerTrustRoot node in a PPS + * MO. + */ + public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; + + /** + * The reason code for provisioning failure when there is no TrustRoot node for remediation + * server in a PPS MO. + */ + public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; + + /** + * The reason code for provisioning failure when there is no TrustRoot node for policy server in + * a PPS MO. + */ + public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; + + /** + * The reason code for provisioning failure when failing to retrieve trust root certificates + * used for validating server certificate for AAA, Remediation and Policy server. + */ + public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; + + /** + * The reason code for provisioning failure when there is no trust root certificate for AAA + * server. + */ + public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; + + /** + * The reason code for provisioning failure when a {@link PasspointConfiguration} is failed to + * install. + */ + public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; + + /** * The status code for provisioning flow to indicate connecting to OSU AP */ public static final int OSU_STATUS_AP_CONNECTING = 1; @@ -158,6 +200,12 @@ public abstract class ProvisioningCallback { public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; /** + * The status code for provisioning flow to indicate starting a step retrieving trust root + * certs. + */ + public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; + + /** * Provisioning status for OSU failure * * @param status indicates error condition @@ -170,5 +218,10 @@ public abstract class ProvisioningCallback { * @param status indicates status of OSU flow */ public abstract void onProvisioningStatus(int status); + + /** + * Provisioning complete when provisioning/remediation flow completes + */ + public abstract void onProvisioningComplete(); } |