diff options
171 files changed, 3466 insertions, 1715 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 1983fb483ecd..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 @@ -5676,6 +5677,7 @@ package android.app { method public java.lang.CharSequence getName(); method public android.net.Uri getSound(); method public long[] getVibrationPattern(); + method public boolean hasUserSetImportance(); method public void setBypassDnd(boolean); method public void setDescription(java.lang.String); method public void setGroup(java.lang.String); @@ -6320,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; @@ -15316,20 +15319,9 @@ package android.graphics.fonts { method public java.nio.ByteBuffer getBuffer(); method public java.io.File getFile(); method public android.os.LocaleList getLocaleList(); + method public int getSlant(); method public int getTtcIndex(); method public int getWeight(); - method public boolean isItalic(); - field public static final int FONT_WEIGHT_BLACK = 900; // 0x384 - field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc - field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320 - field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8 - field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c - field public static final int FONT_WEIGHT_MAX = 1000; // 0x3e8 - field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4 - field public static final int FONT_WEIGHT_MIN = 1; // 0x1 - field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190 - field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258 - field public static final int FONT_WEIGHT_THIN = 100; // 0x64 } public static class Font.Builder { @@ -15342,7 +15334,7 @@ package android.graphics.fonts { method public android.graphics.fonts.Font build() throws java.io.IOException; method public android.graphics.fonts.Font.Builder setFontVariationSettings(java.lang.String); method public android.graphics.fonts.Font.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); - method public android.graphics.fonts.Font.Builder setItalic(boolean); + method public android.graphics.fonts.Font.Builder setSlant(int); method public android.graphics.fonts.Font.Builder setTtcIndex(int); method public android.graphics.fonts.Font.Builder setWeight(int); } @@ -15358,6 +15350,26 @@ package android.graphics.fonts { method public android.graphics.fonts.FontFamily build(); } + public final class FontStyle { + ctor public FontStyle(); + ctor public FontStyle(int, int); + method public int getSlant(); + method public int getWeight(); + field public static final int FONT_SLANT_ITALIC = 1; // 0x1 + field public static final int FONT_SLANT_UPRIGHT = 0; // 0x0 + field public static final int FONT_WEIGHT_BLACK = 900; // 0x384 + field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc + field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320 + field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8 + field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c + field public static final int FONT_WEIGHT_MAX = 1000; // 0x3e8 + field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4 + field public static final int FONT_WEIGHT_MIN = 1; // 0x1 + field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190 + field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258 + field public static final int FONT_WEIGHT_THIN = 100; // 0x64 + } + public final class FontVariationAxis { ctor public FontVariationAxis(java.lang.String, float); method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String); @@ -29733,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 39d24ee2fe6c..7f6e41c1092f 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. @@ -184,7 +185,6 @@ message Atom { DiskIo disk_io = 10032; PowerProfile power_profile = 10033; ProcStats proc_stats_pkg_proc = 10034; - ProcessCpuTime process_cpu_time = 10035; NativeProcessMemoryState native_process_memory_state = 10036; } @@ -1438,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 @@ -3036,22 +3109,6 @@ message PowerProfile { } /** - * Pulls process user time and system time. Puller takes a snapshot of all pids - * in the system and returns cpu stats for those that are working at the time. - * Dead pids will be dropped. Kernel processes are excluded. - * Min cool-down is 5 sec. - */ -message ProcessCpuTime { - optional int32 uid = 1 [(is_uid) = true]; - - optional string process_name = 2; - // Process cpu time in user space, cumulative from boot/process start - optional int64 user_time_millis = 3; - // Process cpu time in system space, cumulative from boot/process start - optional int64 system_time_millis = 4; -} - -/** * Logs when a user restriction was added or removed. * * Logged from: diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 8871d4d054c5..1a9ba8a8de17 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -229,9 +229,6 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // PowerProfile constants for power model calculations. {android::util::POWER_PROFILE, {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, - // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses. - {android::util::PROCESS_CPU_TIME, - {{}, {}, 5 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { 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/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 848def63177e..9f93e1765da3 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -603,9 +603,10 @@ public final class NotificationChannel implements Parcelable { } /** - * @hide + * Returns whether the user has chosen the importance of this channel, either to affirm the + * initial selection from the app, or changed it to be higher or lower. */ - public boolean isImportanceLocked() { + public boolean hasUserSetImportance() { return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; } 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/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index d7fe15d0e925..b8e03876a836 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -737,7 +737,8 @@ public abstract class NotificationListenerService extends Service { * <p>This method will throw a security exception if you don't have access to notifications * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated - * device} in order to use this method. + * device} or be the {@link NotificationAssistantService notification assistant} in order to + * use this method. * * @param pkg The package to retrieve channels for. */ @@ -760,7 +761,8 @@ public abstract class NotificationListenerService extends Service { * <p>This method will throw a security exception if you don't have access to notifications * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated - * device} in order to use this method. + * device} or be the {@link NotificationAssistantService notification assistant} in order to + * use this method. * * @param pkg The package to retrieve channel groups for. */ diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 0808cdd6aedb..3ab8a0a8885f 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1806,6 +1806,7 @@ public abstract class Layout { } } + /** * Fills in the specified Path with a representation of a cursor * at the specified offset. This will often be a vertical line @@ -1821,7 +1822,6 @@ public abstract class Layout { boolean clamped = shouldClampCursor(line); float h1 = getPrimaryHorizontal(point, clamped) - 0.5f; - float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point, clamped) - 0.5f : h1; int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) | TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING); @@ -1839,34 +1839,24 @@ public abstract class Layout { if (h1 < 0.5f) h1 = 0.5f; - if (h2 < 0.5f) - h2 = 0.5f; - if (Float.compare(h1, h2) == 0) { - dest.moveTo(h1, top); - dest.lineTo(h1, bottom); - } else { - dest.moveTo(h1, top); - dest.lineTo(h1, (top + bottom) >> 1); - - dest.moveTo(h2, (top + bottom) >> 1); - dest.lineTo(h2, bottom); - } + dest.moveTo(h1, top); + dest.lineTo(h1, bottom); if (caps == 2) { - dest.moveTo(h2, bottom); - dest.lineTo(h2 - dist, bottom + dist); - dest.lineTo(h2, bottom); - dest.lineTo(h2 + dist, bottom + dist); + dest.moveTo(h1, bottom); + dest.lineTo(h1 - dist, bottom + dist); + dest.lineTo(h1, bottom); + dest.lineTo(h1 + dist, bottom + dist); } else if (caps == 1) { - dest.moveTo(h2, bottom); - dest.lineTo(h2 - dist, bottom + dist); + dest.moveTo(h1, bottom); + dest.lineTo(h1 - dist, bottom + dist); - dest.moveTo(h2 - dist, bottom + dist - 0.5f); - dest.lineTo(h2 + dist, bottom + dist - 0.5f); + dest.moveTo(h1 - dist, bottom + dist - 0.5f); + dest.lineTo(h1 + dist, bottom + dist - 0.5f); - dest.moveTo(h2 + dist, bottom + dist); - dest.lineTo(h2, bottom); + dest.moveTo(h1 + dist, bottom + dist); + dest.lineTo(h1, bottom); } if (fn == 2) { diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index f846a356d8fa..23557694a48d 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -22,7 +22,7 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.LeakyTypefaceStorage; import android.graphics.Typeface; -import android.graphics.fonts.Font; +import android.graphics.fonts.FontStyle; import android.os.LocaleList; import android.os.Parcel; import android.text.ParcelableSpan; @@ -490,7 +490,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl if (styledTypeface != null) { final Typeface readyTypeface; if (mTextFontWeight >= 0) { - final int weight = Math.min(Font.FONT_WEIGHT_MAX, mTextFontWeight); + final int weight = Math.min(FontStyle.FONT_WEIGHT_MAX, mTextFontWeight); final boolean italic = (style & Typeface.ITALIC) != 0; readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic)); } else { 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/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3dd6fd1410bd..66809dbc4e45 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -63,7 +63,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; -import android.graphics.fonts.Font; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.icu.text.DecimalFormatSymbols; import android.os.AsyncTask; @@ -2073,7 +2073,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName, @XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style, - @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) { + @IntRange(from = -1, to = FontStyle.FONT_WEIGHT_MAX) int weight) { if (typeface == null && familyName != null) { // Lookup normal Typeface from system font map. final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL); @@ -2100,9 +2100,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style, - @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) { + @IntRange(from = -1, to = FontStyle.FONT_WEIGHT_MAX) int weight) { if (weight >= 0) { - weight = Math.min(Font.FONT_WEIGHT_MAX, weight); + weight = Math.min(FontStyle.FONT_WEIGHT_MAX, weight); final boolean italic = (style & Typeface.ITALIC) != 0; setTypeface(Typeface.create(typeface, weight, italic)); } else { 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/res/res/values/strings.xml b/core/res/res/values/strings.xml index fa4406185218..9ea82a9b9c2e 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2924,55 +2924,55 @@ <!-- Title for EditText context menu [CHAR LIMIT=20] --> <string name="editTextMenuTitle">Text actions</string> - <!-- Label for item in the text selection menu to trigger an Email app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger an Email app. Should be a verb. [CHAR LIMIT=30] --> <string name="email">Email</string> <!-- Accessibility description for an item in the text selection menu to trigger an Email app [CHAR LIMIT=NONE] --> <string name="email_desc">Email selected address</string> - <!-- Label for item in the text selection menu to trigger a Dialer app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger a Dialer app. Should be a verb. [CHAR LIMIT=30] --> <string name="dial">Call</string> <!-- Accessibility description for an item in the text selection menu to call a phone number [CHAR LIMIT=NONE] --> <string name="dial_desc">Call selected phone number</string> - <!-- Label for item in the text selection menu to trigger a Map app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger a Map app. Should be a verb. [CHAR LIMIT=30] --> <string name="map">Map</string> <!-- Accessibility description for an item in the text selection menu to open maps for an address [CHAR LIMIT=NONE] --> <string name="map_desc">Locate selected address</string> - <!-- Label for item in the text selection menu to trigger a Browser app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger a Browser app. Should be a verb. [CHAR LIMIT=30] --> <string name="browse">Open</string> <!-- Accessibility description for an item in the text selection menu to open a URL in a browser [CHAR LIMIT=NONE] --> <string name="browse_desc">Open selected URL</string> - <!-- Label for item in the text selection menu to trigger an SMS app. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger an SMS app. Should be a verb. [CHAR LIMIT=30] --> <string name="sms">Message</string> <!-- Accessibility description for an item in the text selection menu to send an SMS to a phone number [CHAR LIMIT=NONE] --> <string name="sms_desc">Message selected phone number</string> - <!-- Label for item in the text selection menu to trigger adding a contact. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to trigger adding a contact. Should be a verb. [CHAR LIMIT=30] --> <string name="add_contact">Add</string> <!-- Accessibility description for an item in the text selection menu to add the selected detail to contacts [CHAR LIMIT=NONE] --> <string name="add_contact_desc">Add to contacts</string> - <!-- Label for item in the text selection menu to view the calendar for the selected time/date. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to view the calendar for the selected time/date. Should be a verb. [CHAR LIMIT=30] --> <string name="view_calendar">View</string> <!-- Accessibility description for an item in the text selection menu to view the calendar for a date [CHAR LIMIT=NONE]--> <string name="view_calendar_desc">View selected time in calendar</string> - <!-- Label for item in the text selection menu to create a calendar event at the selected time/date. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to create a calendar event at the selected time/date. Should be a verb. [CHAR LIMIT=30] --> <string name="add_calendar_event">Schedule</string> <!-- Accessibility description for an item in the text selection menu to schedule an event for a date [CHAR LIMIT=NONE] --> <string name="add_calendar_event_desc">Schedule event for selected time</string> - <!-- Label for item in the text selection menu to track a selected flight number. Should be a verb. [CHAR LIMIT=20] --> + <!-- Label for item in the text selection menu to track a selected flight number. Should be a verb. [CHAR LIMIT=30] --> <string name="view_flight">Track</string> <!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] --> diff --git a/core/tests/coretests/assets/fonts/1em_bidi_font.ttf b/core/tests/coretests/assets/fonts/1em_bidi_font.ttf Binary files differnew file mode 100644 index 000000000000..459925433349 --- /dev/null +++ b/core/tests/coretests/assets/fonts/1em_bidi_font.ttf diff --git a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java new file mode 100644 index 000000000000..1208d7ca194a --- /dev/null +++ b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text; + +import static org.junit.Assert.assertArrayEquals; + +import android.content.Context; +import android.graphics.Path; +import android.graphics.Typeface; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.text.method.MetaKeyKeyListener; +import android.view.KeyEvent; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class LayoutBidiCursorPathTest { + + private static final float BIDI_TEXT_SIZE = 12f; + private static final String LTR_TEXT = "hello"; + private static final String RTL_TEXT = "Ù…Ø±ØØ¨Ø§"; + + private SpannableStringBuilder mBidiText; + private TextPaint mTextPaint; + + @Before + public void setup() { + mBidiText = new SpannableStringBuilder(LTR_TEXT + RTL_TEXT); + + final Context context = InstrumentationRegistry.getTargetContext(); + mTextPaint = new TextPaint(); + mTextPaint.setTypeface( + Typeface.createFromAsset(context.getAssets(), "fonts/1em_bidi_font.ttf")); + mTextPaint.setTextSize(BIDI_TEXT_SIZE); + } + + @Test + public void testGetCursorPathSegments() { + // Setup layout and Act. + final Path actualPath = new Path(); + setupLayoutAndGetCursorPath(actualPath); + + // Expected path. + final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; + final int top = 0; + // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. + final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); + + final Path expectedPath = new Path(); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1, bottom); + + // Assert. + assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); + } + + @Test + public void testGetCursorPath_whenShiftIsPressed() { + // When shift is pressed a triangle is drawn at the bottom quarter of the cursor. + // Set up key. + final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; + metaKeyKeyListener + .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_SHIFT_RIGHT, null /*keyEvent*/); + + // Setup layout and Act. + final Path actualPath = new Path(); + setupLayoutAndGetCursorPath(actualPath); + + // Expected path. + final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; + final int top = 0; + // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. + int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); + // Draw a triangle at the bottom quarter of the cursor, thus cut the cursor to its 3/4 + // length. + final int dist = (bottom - top) / 4; + bottom -= dist; + + final Path expectedPath = new Path(); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1, bottom); + + expectedPath.moveTo(h1, bottom); + expectedPath.lineTo(h1 - dist, bottom + dist); + + expectedPath.moveTo(h1 - dist, bottom + dist - 0.5f); + expectedPath.lineTo(h1 + dist, bottom + dist - 0.5f); + + expectedPath.moveTo(h1 + dist, bottom + dist); + expectedPath.lineTo(h1, bottom); + + // Assert. + assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); + } + + @Test + public void testGetCursorPath_whenAltIsPressed() { + // When alt is pressed a triangle is drawn at the top quarter of the cursor. + // Set up key. + final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; + metaKeyKeyListener + .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_ALT_RIGHT, null /*keyEvent*/); + + // Setup layout and Act. + final Path actualPath = new Path(); + setupLayoutAndGetCursorPath(actualPath); + + // Expected path. + final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; + int top = 0; + // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. + final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); + // Draw a triangle at the top quarter of the cursor, thus cut the cursor to its 3/4 length. + final int dist = (bottom - top) / 4; + top += dist; + + final Path expectedPath = new Path(); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1, bottom); + + expectedPath.moveTo(h1, top); + expectedPath.lineTo(h1 - dist, top - dist); + + expectedPath.moveTo(h1 - dist, top - dist + 0.5f); + expectedPath.lineTo(h1 + dist, top - dist + 0.5f); + + expectedPath.moveTo(h1 + dist, top - dist); + expectedPath.lineTo(h1, top); + + // Assert. + assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); + } + + private void setupLayoutAndGetCursorPath(Path path) { + final Layout layout = StaticLayout.Builder.obtain( + mBidiText, 0, mBidiText.length(), mTextPaint, Integer.MAX_VALUE) + .setIncludePad(false) + .build(); + + layout.getCursorPath(LTR_TEXT.length(), path, mBidiText); + } +} 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/Typeface.java b/graphics/java/android/graphics/Typeface.java index 7ad207f339d1..ba47300210cd 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -27,6 +27,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.net.Uri; @@ -148,7 +149,7 @@ public class Typeface { @UnsupportedAppUsage private @Style int mStyle = 0; - private @IntRange(from = 0, to = android.graphics.fonts.Font.FONT_WEIGHT_MAX) int mWeight = 0; + private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) int mWeight = 0; // Value for weight and italic. Indicates the value is resolved by font metadata. // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp 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/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index bd1ac25bf8df..f426b2d3465b 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -51,61 +51,6 @@ public final class Font { private static final int STYLE_NORMAL = 0; /** - * A minimum weight value for the font - */ - public static final int FONT_WEIGHT_MIN = 1; - - /** - * A font weight value for the thin weight - */ - public static final int FONT_WEIGHT_THIN = 100; - - /** - * A font weight value for the extra-light weight - */ - public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; - - /** - * A font weight value for the light weight - */ - public static final int FONT_WEIGHT_LIGHT = 300; - - /** - * A font weight value for the normal weight - */ - public static final int FONT_WEIGHT_NORMAL = 400; - - /** - * A font weight value for the medium weight - */ - public static final int FONT_WEIGHT_MEDIUM = 500; - - /** - * A font weight value for the semi-bold weight - */ - public static final int FONT_WEIGHT_SEMI_BOLD = 600; - - /** - * A font weight value for the bold weight. - */ - public static final int FONT_WEIGHT_BOLD = 700; - - /** - * A font weight value for the extra-bold weight - */ - public static final int FONT_WEIGHT_EXTRA_BOLD = 800; - - /** - * A font weight value for the black weight - */ - public static final int FONT_WEIGHT_BLACK = 900; - - /** - * A maximum weight value for the font - */ - public static final int FONT_WEIGHT_MAX = 1000; - - /** * A builder class for creating new Font. */ public static class Builder { @@ -275,66 +220,68 @@ public final class Font { * <tr> * <td align="center">100</td> * <td align="center">Thin</td> - * <td align="center">{@link Font#FONT_WEIGHT_THIN}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_THIN}</td> * </tr> * <tr> * <td align="center">200</td> * <td align="center">Extra Light (Ultra Light)</td> - * <td align="center">{@link Font#FONT_WEIGHT_EXTRA_LIGHT}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_LIGHT}</td> * </tr> * <tr> * <td align="center">300</td> * <td align="center">Light</td> - * <td align="center">{@link Font#FONT_WEIGHT_LIGHT}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_LIGHT}</td> * </tr> * <tr> * <td align="center">400</td> * <td align="center">Normal (Regular)</td> - * <td align="center">{@link Font#FONT_WEIGHT_NORMAL}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_NORMAL}</td> * </tr> * <tr> * <td align="center">500</td> * <td align="center">Medium</td> - * <td align="center">{@link Font#FONT_WEIGHT_MEDIUM}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_MEDIUM}</td> * </tr> * <tr> * <td align="center">600</td> * <td align="center">Semi Bold (Demi Bold)</td> - * <td align="center">{@link Font#FONT_WEIGHT_SEMI_BOLD}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_SEMI_BOLD}</td> * </tr> * <tr> * <td align="center">700</td> * <td align="center">Bold</td> - * <td align="center">{@link Font#FONT_WEIGHT_BOLD}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BOLD}</td> * </tr> * <tr> * <td align="center">800</td> * <td align="center">Extra Bold (Ultra Bold)</td> - * <td align="center">{@link Font#FONT_WEIGHT_EXTRA_BOLD}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_BOLD}</td> * </tr> * <tr> * <td align="center">900</td> * <td align="center">Black (Heavy)</td> - * <td align="center">{@link Font#FONT_WEIGHT_BLACK}</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BLACK}</td> * </tr> * </tbody> * </p> * - * @see Font#FONT_WEIGHT_THIN - * @see Font#FONT_WEIGHT_EXTRA_LIGHT - * @see Font#FONT_WEIGHT_LIGHT - * @see Font#FONT_WEIGHT_NORMAL - * @see Font#FONT_WEIGHT_MEDIUM - * @see Font#FONT_WEIGHT_SEMI_BOLD - * @see Font#FONT_WEIGHT_BOLD - * @see Font#FONT_WEIGHT_EXTRA_BOLD - * @see Font#FONT_WEIGHT_BLACK + * @see FontStyle#FONT_WEIGHT_THIN + * @see FontStyle#FONT_WEIGHT_EXTRA_LIGHT + * @see FontStyle#FONT_WEIGHT_LIGHT + * @see FontStyle#FONT_WEIGHT_NORMAL + * @see FontStyle#FONT_WEIGHT_MEDIUM + * @see FontStyle#FONT_WEIGHT_SEMI_BOLD + * @see FontStyle#FONT_WEIGHT_BOLD + * @see FontStyle#FONT_WEIGHT_EXTRA_BOLD + * @see FontStyle#FONT_WEIGHT_BLACK * @param weight a weight value * @return this builder */ public @NonNull Builder setWeight( - @IntRange(from = FONT_WEIGHT_MIN, to = FONT_WEIGHT_MAX) int weight) { - Preconditions.checkArgument(FONT_WEIGHT_MIN <= weight && weight <= FONT_WEIGHT_MAX); + @IntRange(from = FontStyle.FONT_WEIGHT_MIN, to = FontStyle.FONT_WEIGHT_MAX) + int weight) { + Preconditions.checkArgument( + FontStyle.FONT_WEIGHT_MIN <= weight && weight <= FontStyle.FONT_WEIGHT_MAX); mWeight = weight; return this; } @@ -346,13 +293,12 @@ public final class Font { * will resolve the style by reading font tables. * * For example, if you want to use italic font as upright font, call {@code - * setItalic(false)} explicitly. + * setSlant(false)} explicitly. * - * @param italic {@code true} if the font is italic. Otherwise {@code false}. * @return this builder */ - public @NonNull Builder setItalic(boolean italic) { - mItalic = italic ? STYLE_ITALIC : STYLE_NORMAL; + public @NonNull Builder setSlant(@FontStyle.FontSlant int slant) { + mItalic = slant == FontStyle.FONT_SLANT_UPRIGHT ? STYLE_NORMAL : STYLE_ITALIC; return this; } @@ -414,8 +360,11 @@ public final class Font { mItalic = STYLE_NORMAL; } } - mWeight = Math.max(FONT_WEIGHT_MIN, Math.min(FONT_WEIGHT_MAX, mWeight)); + mWeight = Math.max(FontStyle.FONT_WEIGHT_MIN, + Math.min(FontStyle.FONT_WEIGHT_MAX, mWeight)); final boolean italic = (mItalic == STYLE_ITALIC); + final int slant = (mItalic == STYLE_ITALIC) + ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT; final long builderPtr = nInitBuilder(); if (mAxes != null) { for (FontVariationAxis axis : mAxes) { @@ -424,8 +373,8 @@ public final class Font { } final ByteBuffer readonlyBuffer = mBuffer.asReadOnlyBuffer(); final long ptr = nBuild(builderPtr, readonlyBuffer, mWeight, italic, mTtcIndex); - final Font font = new Font(ptr, readonlyBuffer, mFile, mWeight, italic, mTtcIndex, - mAxes, mLocaleList); + final Font font = new Font(ptr, readonlyBuffer, mFile, + new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList); sFontRegistory.registerNativeAllocation(font, ptr); return font; } @@ -454,8 +403,7 @@ public final class Font { private final long mNativePtr; // address of the shared ptr of minikin::Font private final @NonNull ByteBuffer mBuffer; private final @Nullable File mFile; - private final @IntRange(from = 0, to = 1000) int mWeight; - private final boolean mItalic; + private final FontStyle mFontStyle; private final @IntRange(from = 0) int mTtcIndex; private final @Nullable FontVariationAxis[] mAxes; private final @NonNull String mLocaleList; @@ -464,13 +412,11 @@ public final class Font { * Use Builder instead */ private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file, - @IntRange(from = 0, to = 1000) int weight, boolean italic, - @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes, - @NonNull String localeList) { + @NonNull FontStyle fontStyle, @IntRange(from = 0) int ttcIndex, + @Nullable FontVariationAxis[] axes, @NonNull String localeList) { mBuffer = buffer; mFile = file; - mWeight = weight; - mItalic = italic; + mFontStyle = fontStyle; mNativePtr = nativePtr; mTtcIndex = ttcIndex; mAxes = axes; @@ -504,17 +450,17 @@ public final class Font { * @return a weight value */ public @IntRange(from = 0, to = 1000)int getWeight() { - return mWeight; + return mFontStyle.getWeight(); } /** - * Returns true if this font is marked as italic, otherwise returns false. + * Get a slant value associated with this font. * - * @see Builder#setItalic(boolean) - * @return true if italic, otherwise false + * @see Builder#setSlant(boolean) + * @return a slant value */ - public boolean isItalic() { - return mItalic; + public @FontStyle.FontSlant int getSlant() { + return mFontStyle.getSlant(); } /** @@ -564,21 +510,20 @@ public final class Font { return false; } Font f = (Font) o; - return f.mWeight == mWeight && f.mItalic == mItalic && f.mTtcIndex == mTtcIndex + return mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer); } @Override public int hashCode() { - return Objects.hash(mWeight, mItalic, mTtcIndex, Arrays.hashCode(mAxes), mBuffer); + return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer); } @Override public String toString() { return "Font {" + "path=" + mFile - + ", weight=" + mWeight - + ", italic=" + mItalic + + ", style=" + mFontStyle + ", ttcIndex=" + mTtcIndex + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes) + ", localeList=" + mLocaleList diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java index 3bcdc31a3160..52a37da47cff 100644 --- a/graphics/java/android/graphics/fonts/FontFamily.java +++ b/graphics/java/android/graphics/fonts/FontFamily.java @@ -124,7 +124,7 @@ public final class FontFamily { } private static int makeStyleIdentifier(@NonNull Font font) { - return font.getWeight() | (font.isItalic() ? (1 << 16) : 0); + return font.getWeight() | (font.getSlant() << 16); } private static native long nInitBuilder(); diff --git a/graphics/java/android/graphics/fonts/FontStyle.java b/graphics/java/android/graphics/fonts/FontStyle.java new file mode 100644 index 000000000000..82fc7ac01772 --- /dev/null +++ b/graphics/java/android/graphics/fonts/FontStyle.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.fonts; + +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.Nullable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * A font style object. + * + * This class represents a single font style which is a pair of weight value and slant value. + * Here are common font styles examples: + * <p> + * <pre> + * <code> + * final FontStyle NORMAL = new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT); + * final FontStyle BOLD = new FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_UPRIGHT); + * final FontStyle ITALIC = new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC); + * final FontStyle BOLD_ITALIC = new FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_ITALIC); + * </code> + * </pre> + * </p> + * + */ +public final class FontStyle { + private static final String TAG = "FontStyle"; + + /** + * A minimum weight value for the font + */ + public static final int FONT_WEIGHT_MIN = 1; + + /** + * A font weight value for the thin weight + */ + public static final int FONT_WEIGHT_THIN = 100; + + /** + * A font weight value for the extra-light weight + */ + public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; + + /** + * A font weight value for the light weight + */ + public static final int FONT_WEIGHT_LIGHT = 300; + + /** + * A font weight value for the normal weight + */ + public static final int FONT_WEIGHT_NORMAL = 400; + + /** + * A font weight value for the medium weight + */ + public static final int FONT_WEIGHT_MEDIUM = 500; + + /** + * A font weight value for the semi-bold weight + */ + public static final int FONT_WEIGHT_SEMI_BOLD = 600; + + /** + * A font weight value for the bold weight. + */ + public static final int FONT_WEIGHT_BOLD = 700; + + /** + * A font weight value for the extra-bold weight + */ + public static final int FONT_WEIGHT_EXTRA_BOLD = 800; + + /** + * A font weight value for the black weight + */ + public static final int FONT_WEIGHT_BLACK = 900; + + /** + * A maximum weight value for the font + */ + public static final int FONT_WEIGHT_MAX = 1000; + + /** + * A font slant value for upright + */ + public static final int FONT_SLANT_UPRIGHT = 0; + + /** + * A font slant value for italic + */ + public static final int FONT_SLANT_ITALIC = 1; + + // TODO: Support FONT_SLANT_OBLIQUE + + /** @hide */ + @IntDef(prefix = { "FONT_SLANT_" }, value = { + FONT_SLANT_UPRIGHT, + FONT_SLANT_ITALIC + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FontSlant {} + + private final @IntRange(from = 0, to = 1000) int mWeight; + private final @FontSlant int mSlant; + // TODO: Support width + + public FontStyle() { + mWeight = FONT_WEIGHT_NORMAL; + mSlant = FONT_SLANT_UPRIGHT; + } + + /** + * Create FontStyle with specific weight and italic + * + * <p> + * <table> + * <thead> + * <tr> + * <th align="center">Value</th> + * <th align="center">Name</th> + * <th align="center">Android Definition</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">100</td> + * <td align="center">Thin</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_THIN}</td> + * </tr> + * <tr> + * <td align="center">200</td> + * <td align="center">Extra Light (Ultra Light)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_LIGHT}</td> + * </tr> + * <tr> + * <td align="center">300</td> + * <td align="center">Light</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_LIGHT}</td> + * </tr> + * <tr> + * <td align="center">400</td> + * <td align="center">Normal (Regular)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_NORMAL}</td> + * </tr> + * <tr> + * <td align="center">500</td> + * <td align="center">Medium</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_MEDIUM}</td> + * </tr> + * <tr> + * <td align="center">600</td> + * <td align="center">Semi Bold (Demi Bold)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_SEMI_BOLD}</td> + * </tr> + * <tr> + * <td align="center">700</td> + * <td align="center">Bold</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BOLD}</td> + * </tr> + * <tr> + * <td align="center">800</td> + * <td align="center">Extra Bold (Ultra Bold)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_EXTRA_BOLD}</td> + * </tr> + * <tr> + * <td align="center">900</td> + * <td align="center">Black (Heavy)</td> + * <td align="center">{@link FontStyle#FONT_WEIGHT_BLACK}</td> + * </tr> + * </tbody> + * </p> + * + * @see FontStyle#FONT_WEIGHT_THIN + * @see FontStyle#FONT_WEIGHT_EXTRA_LIGHT + * @see FontStyle#FONT_WEIGHT_LIGHT + * @see FontStyle#FONT_WEIGHT_NORMAL + * @see FontStyle#FONT_WEIGHT_MEDIUM + * @see FontStyle#FONT_WEIGHT_SEMI_BOLD + * @see FontStyle#FONT_WEIGHT_BOLD + * @see FontStyle#FONT_WEIGHT_EXTRA_BOLD + * @see FontStyle#FONT_WEIGHT_BLACK + * @param weight a weight value + * @param slant a slant value + */ + public FontStyle(int weight, @FontSlant int slant) { + Preconditions.checkArgument(FONT_WEIGHT_MIN <= weight && weight <= FONT_WEIGHT_MAX, + "weight value must be [" + FONT_WEIGHT_MIN + ", " + FONT_WEIGHT_MAX + "]"); + Preconditions.checkArgument(slant == FONT_SLANT_UPRIGHT || slant == FONT_SLANT_ITALIC, + "slant value must be FONT_SLANT_UPRIGHT or FONT_SLANT_UPRIGHT"); + mWeight = weight; + mSlant = slant; + } + + + /** + * Gets the weight value + * + * @see FontStyle#setWeight(int) + * @return a weight value + */ + public @IntRange(from = 0, to = 1000) int getWeight() { + return mWeight; + } + + /** + * Gets the slant value + * + * @return a slant value + */ + public @FontSlant int getSlant() { + return mSlant; + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + if (o == null || !(o instanceof FontStyle)) { + return false; + } + FontStyle fontStyle = (FontStyle) o; + return fontStyle.mWeight == mWeight && fontStyle.mSlant == mSlant; + } + + @Override + public int hashCode() { + return Objects.hash(mWeight, mSlant); + } + + @Override + public String toString() { + return "FontStyle { weight=" + mWeight + ", slant=" + mSlant + "}"; + } +} diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 2d21bbbd4e43..750adb2757c8 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -192,7 +192,8 @@ public final class SystemFonts { try { font = new Font.Builder(buffer, new File(fullPath), languageTags) .setWeight(fontConfig.getWeight()) - .setItalic(fontConfig.isItalic()) + .setSlant(fontConfig.isItalic() ? FontStyle.FONT_SLANT_ITALIC + : FontStyle.FONT_SLANT_UPRIGHT) .setTtcIndex(fontConfig.getTtcIndex()) .setFontVariationSettings(fontConfig.getAxes()) .build(); 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/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index 0022c931c45e..c6e4c154b41e 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -141,7 +141,7 @@ uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) { // select only flags that might affect text layout flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag | - SkPaint::kAutoHinting_Flag | SkPaint::kVerticalText_Flag); + SkPaint::kAutoHinting_Flag); flags |= (hinting << 16); return flags; } 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/ExtServices/src/android/ext/services/notification/AgingHelper.java b/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java index 5782ea100070..31c9224a8489 100644 --- a/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/AgingHelper.java @@ -66,7 +66,7 @@ public class AgingHelper { public void onNotificationSeen(NotificationEntry entry) { // user has strong opinions about this notification. we can't down rank it, so don't bother. - if (entry.getChannel().isImportanceLocked()) { + if (entry.getChannel().hasUserSetImportance()) { return; } 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/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/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/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/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 7fa042655e53..1495abf9310c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -793,7 +793,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/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 0bc54a33347c..659f6c75c703 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 @@ -5654,19 +5654,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. + mStatusBar.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/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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 75077029c16b..e31bad65dbb2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -38,6 +38,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; @@ -104,6 +105,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 +286,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(); @@ -573,7 +585,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); @@ -1235,6 +1247,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 +2353,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(); } @@ -2769,11 +2781,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 +2802,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; @@ -2989,4 +3018,22 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setScrimController(scrimController); updateShowEmptyShadeView(); } + + /** + * 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/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/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index cc9adb86a6b4..56e5a1e1bd6f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3617,7 +3617,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(); @@ -4203,7 +4204,6 @@ public class StatusBar extends SystemUI implements DemoMode, mAmbientPulseManager.releaseAllImmediately(); mVisualStabilityManager.setScreenOn(true); mNotificationPanel.setTouchAndAnimationDisabled(false); - mDozeServiceHost.stopDozing(); updateVisibleToUser(); updateIsKeyguard(); updateScrimController(); @@ -4401,6 +4401,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 +4415,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 +4436,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 +4520,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 +4643,10 @@ public class StatusBar extends SystemUI implements DemoMode, public boolean shouldAnimateScreenOff() { return mAnimateScreenOff; } + + public boolean wasPassivelyInterrupted() { + return mPassivelyInterrupted; + } } public boolean shouldIgnoreTouch() { 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/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/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/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 9a47553bf446..ede13ef66ac4 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -873,6 +873,52 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> return null; } + ActivityRecord topRunningActivity() { + return topRunningActivity(false /* considerKeyguardState */); + } + + /** + * Returns the top running activity in the focused stack. In the case the focused stack has no + * such activity, the next focusable stack on this display is returned. + * + * @param considerKeyguardState Indicates whether the locked state should be considered. if + * {@code true} and the keyguard is locked, only activities that + * can be shown on top of the keyguard will be considered. + * @return The top running activity. {@code null} if none is available. + */ + ActivityRecord topRunningActivity(boolean considerKeyguardState) { + ActivityRecord topRunning = null; + final ActivityStack focusedStack = getFocusedStack(); + if (focusedStack != null) { + topRunning = focusedStack.topRunningActivityLocked(); + } + + // Look in other focusable stacks. + if (topRunning == null) { + for (int i = mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = mStacks.get(i); + // Only consider focusable stacks other than the current focused one. + if (stack == focusedStack || !stack.isFocusable()) { + continue; + } + topRunning = stack.topRunningActivityLocked(); + if (topRunning != null) { + break; + } + } + } + + // This activity can be considered the top running activity if we are not considering + // the locked state, the keyguard isn't locked, or we can show when locked. + if (topRunning != null && considerKeyguardState + && mSupervisor.getKeyguardController().isKeyguardLocked() + && !topRunning.canShowWhenLocked()) { + return null; + } + + return topRunning; + } + int getIndexOf(ActivityStack stack) { return mStacks.indexOf(stack); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index afb7a7211eb4..7a0a742bfae7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -22,6 +22,8 @@ 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; @@ -462,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]; @@ -7133,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, @@ -7172,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; @@ -14698,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 @@ -14715,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); @@ -14728,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 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/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 12ed726eca77..026c5cc3017d 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3877,8 +3877,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // The activity that we are finishing may be over the lock screen. In this case, we do not // want to consider activities that cannot be shown on the lock screen as running and should // proceed with finishing the activity if there is no valid next top running activity. - final ActivityRecord next = mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */); + final ActivityDisplay display = getDisplay(); + final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */); if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible) && next != null && !next.nowVisible) { @@ -3902,23 +3902,25 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r); r.setState(FINISHING, "finishCurrentActivityLocked"); - final boolean finishingActivityInNonFocusedStack - = r.getStack() != mStackSupervisor.getTopDisplayFocusedStack() - && prevState == PAUSED && mode == FINISH_AFTER_VISIBLE; + final boolean finishingInNonFocusedStackOrNoRunning = mode == FINISH_AFTER_VISIBLE + && prevState == PAUSED && (r.getStack() != display.getFocusedStack() + || (next == null && display.topRunningActivity() == null)); if (mode == FINISH_IMMEDIATELY || (prevState == PAUSED && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode())) - || finishingActivityInNonFocusedStack + || finishingInNonFocusedStackOrNoRunning || prevState == STOPPING || prevState == STOPPED || prevState == ActivityState.INITIALIZING) { r.makeFinishingLocked(); boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason); - if (finishingActivityInNonFocusedStack) { + if (finishingInNonFocusedStackOrNoRunning) { // Finishing activity that was in paused state and it was in not currently focused - // stack, need to make something visible in its place. + // stack, need to make something visible in its place. Also if the display does not + // have running activity, the configuration may need to be updated for restoring + // original orientation of the display. mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId, false /* markFrozenIfConfigChanged */, true /* deferResume */); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 90e2f5bcd1b4..257a0042b510 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1214,75 +1214,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord topRunningActivityLocked() { - return topRunningActivityLocked(false /* considerKeyguardState */); - } - - /** - * Returns the top running activity in the focused stack. In the case the focused stack has no - * such activity, the next focusable stack on top of a display is returned. - * @param considerKeyguardState Indicates whether the locked state should be considered. if - * {@code true} and the keyguard is locked, only activities that - * can be shown on top of the keyguard will be considered. - * @return The top running activity. {@code null} if none is available. - */ - ActivityRecord topRunningActivityLocked(boolean considerKeyguardState) { - final ActivityStack focusedStack = getTopDisplayFocusedStack(); - ActivityRecord r = focusedStack.topRunningActivityLocked(); - if (r != null && isValidTopRunningActivity(r, considerKeyguardState)) { - return r; - } - - // Look in other non-focused and non-home stacks. for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - - // TODO: We probably want to consider the top fullscreen stack as we could have a pinned - // stack on top. - final ActivityStack topStack = display.getTopStack(); - - // Only consider focusable top stacks other than the current focused one. - if (topStack == null || !topStack.isFocusable() || topStack == focusedStack) { - continue; - } - - final ActivityRecord topActivity = topStack.topRunningActivityLocked(); - - // Skip if no top activity. - if (topActivity == null) { - continue; - } - - - // This activity can be considered the top running activity if we are not - // considering the locked state, the keyguard isn't locked, or we can show when - // locked. - if (isValidTopRunningActivity(topActivity, considerKeyguardState)) { + final ActivityRecord topActivity = mActivityDisplays.get(i).topRunningActivity(); + if (topActivity != null) { return topActivity; } } - return null; } - /** - * Verifies an {@link ActivityRecord} can be the top activity based on keyguard state and - * whether we are considering it. - */ - private boolean isValidTopRunningActivity(ActivityRecord record, - boolean considerKeyguardState) { - if (!considerKeyguardState) { - return true; - } - - final boolean keyguardLocked = getKeyguardController().isKeyguardLocked(); - - if (!keyguardLocked) { - return true; - } - - return record.canShowWhenLocked(); - } - @VisibleForTesting void getRunningTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 0db77651cb7b..194aa1b7eef6 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -5878,6 +5878,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void finishHeavyWeightApp() { synchronized (mGlobalLock) { + if (mHeavyWeightProcess != null) { + mHeavyWeightProcess.finishActivities(); + } ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals( mHeavyWeightProcess); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 5fdcb9220fca..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") diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 0c66c5b22d76..6989c334d876 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -55,6 +55,8 @@ import java.util.function.Predicate; * Each app can have a different default networks or different connectivity * status due to user-requested network policies, so we need to check * constraints on a per-UID basis. + * + * Test: atest com.android.server.job.controllers.ConnectivityControllerTest */ public final class ConnectivityController extends StateController implements ConnectivityManager.OnNetworkActiveListener { @@ -65,8 +67,9 @@ public final class ConnectivityController extends StateController implements private final ConnectivityManager mConnManager; private final NetworkPolicyManager mNetPolicyManager; + /** List of tracked jobs keyed by source UID. */ @GuardedBy("mLock") - private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>(); + private final SparseArray<ArraySet<JobStatus>> mTrackedJobs = new SparseArray<>(); public ConnectivityController(JobSchedulerService service) { super(service); @@ -87,7 +90,12 @@ public final class ConnectivityController extends StateController implements public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { if (jobStatus.hasConnectivityConstraint()) { updateConstraintsSatisfied(jobStatus); - mTrackedJobs.add(jobStatus); + ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUid()); + if (jobs == null) { + jobs = new ArraySet<>(); + mTrackedJobs.put(jobStatus.getSourceUid(), jobs); + } + jobs.add(jobStatus); jobStatus.setTrackingController(JobStatus.TRACKING_CONNECTIVITY); } } @@ -97,7 +105,10 @@ public final class ConnectivityController extends StateController implements public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { if (jobStatus.clearTrackingController(JobStatus.TRACKING_CONNECTIVITY)) { - mTrackedJobs.remove(jobStatus); + ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUid()); + if (jobs != null) { + jobs.remove(jobStatus); + } } } @@ -235,47 +246,26 @@ public final class ConnectivityController extends StateController implements /** * Update any jobs tracked by this controller that match given filters. * - * @param filterUid only update jobs belonging to this UID, or {@code -1} to - * update all tracked jobs. + * @param filterUid only update jobs belonging to this UID, or {@code -1} to + * update all tracked jobs. * @param filterNetwork only update jobs that would use this - * {@link Network}, or {@code null} to update all tracked jobs. + * {@link Network}, or {@code null} to update all tracked jobs. */ private void updateTrackedJobs(int filterUid, Network filterNetwork) { synchronized (mLock) { // Since this is a really hot codepath, temporarily cache any // answers that we get from ConnectivityManager. - final SparseArray<Network> uidToNetwork = new SparseArray<>(); final SparseArray<NetworkCapabilities> networkToCapabilities = new SparseArray<>(); boolean changed = false; - for (int i = mTrackedJobs.size() - 1; i >= 0; i--) { - final JobStatus js = mTrackedJobs.valueAt(i); - final int uid = js.getSourceUid(); - - final boolean uidMatch = (filterUid == -1 || filterUid == uid); - if (uidMatch) { - Network network = uidToNetwork.get(uid); - if (network == null) { - network = mConnManager.getActiveNetworkForUid(uid); - uidToNetwork.put(uid, network); - } - - // Update either when we have a network match, or when the - // job hasn't yet been evaluated against the currently - // active network; typically when we just lost a network. - final boolean networkMatch = (filterNetwork == null - || Objects.equals(filterNetwork, network)); - final boolean forceUpdate = !Objects.equals(js.network, network); - if (networkMatch || forceUpdate) { - final int netId = network != null ? network.netId : -1; - NetworkCapabilities capabilities = networkToCapabilities.get(netId); - if (capabilities == null) { - capabilities = mConnManager.getNetworkCapabilities(network); - networkToCapabilities.put(netId, capabilities); - } - changed |= updateConstraintsSatisfied(js, network, capabilities); - } + if (filterUid == -1) { + for (int i = mTrackedJobs.size() - 1; i >= 0; i--) { + changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), + filterNetwork, networkToCapabilities); } + } else { + changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), + filterNetwork, networkToCapabilities); } if (changed) { mStateChangedListener.onControllerStateChanged(); @@ -283,6 +273,36 @@ public final class ConnectivityController extends StateController implements } } + private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork, + SparseArray<NetworkCapabilities> networkToCapabilities) { + if (jobs == null || jobs.size() == 0) { + return false; + } + + final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid()); + final int netId = network != null ? network.netId : -1; + NetworkCapabilities capabilities = networkToCapabilities.get(netId); + if (capabilities == null) { + capabilities = mConnManager.getNetworkCapabilities(network); + networkToCapabilities.put(netId, capabilities); + } + final boolean networkMatch = (filterNetwork == null + || Objects.equals(filterNetwork, network)); + + boolean changed = false; + for (int i = jobs.size() - 1; i >= 0; i--) { + final JobStatus js = jobs.valueAt(i); + + // Update either when we have a network match, or when the + // job hasn't yet been evaluated against the currently + // active network; typically when we just lost a network. + if (networkMatch || !Objects.equals(js.network, network)) { + changed |= updateConstraintsSatisfied(js, network, capabilities); + } + } + return changed; + } + /** * We know the network has just come up. We want to run any jobs that are ready. */ @@ -290,12 +310,15 @@ public final class ConnectivityController extends StateController implements public void onNetworkActive() { synchronized (mLock) { for (int i = mTrackedJobs.size()-1; i >= 0; i--) { - final JobStatus js = mTrackedJobs.valueAt(i); - if (js.isReady()) { - if (DEBUG) { - Slog.d(TAG, "Running " + js + " due to network activity."); + final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i); + for (int j = jobs.size() - 1; j >= 0; j--) { + final JobStatus js = jobs.valueAt(j); + if (js.isReady()) { + if (DEBUG) { + Slog.d(TAG, "Running " + js + " due to network activity."); + } + mStateChangedListener.onRunJobNow(js); } - mStateChangedListener.onRunJobNow(js); } } } @@ -334,8 +357,12 @@ public final class ConnectivityController extends StateController implements public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { for (int i = 0; i < mTrackedJobs.size(); i++) { - final JobStatus js = mTrackedJobs.valueAt(i); - if (predicate.test(js)) { + final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i); + for (int j = 0; j < jobs.size(); j++) { + final JobStatus js = jobs.valueAt(j); + if (!predicate.test(js)) { + continue; + } pw.print("#"); js.printUniqueId(pw); pw.print(" from "); @@ -355,20 +382,26 @@ public final class ConnectivityController extends StateController implements final long mToken = proto.start(StateControllerProto.CONNECTIVITY); for (int i = 0; i < mTrackedJobs.size(); i++) { - final JobStatus js = mTrackedJobs.valueAt(i); - if (!predicate.test(js)) { - continue; - } - final long jsToken = proto.start(StateControllerProto.ConnectivityController.TRACKED_JOBS); - js.writeToShortProto(proto, StateControllerProto.ConnectivityController.TrackedJob.INFO); - proto.write(StateControllerProto.ConnectivityController.TrackedJob.SOURCE_UID, - js.getSourceUid()); - NetworkRequest rn = js.getJob().getRequiredNetwork(); - if (rn != null) { - rn.writeToProto(proto, - StateControllerProto.ConnectivityController.TrackedJob.REQUIRED_NETWORK); + final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i); + for (int j = 0; j < jobs.size(); j++) { + final JobStatus js = jobs.valueAt(j); + if (!predicate.test(js)) { + continue; + } + final long jsToken = proto.start( + StateControllerProto.ConnectivityController.TRACKED_JOBS); + js.writeToShortProto(proto, + StateControllerProto.ConnectivityController.TrackedJob.INFO); + proto.write(StateControllerProto.ConnectivityController.TrackedJob.SOURCE_UID, + js.getSourceUid()); + NetworkRequest rn = js.getJob().getRequiredNetwork(); + if (rn != null) { + rn.writeToProto(proto, + StateControllerProto.ConnectivityController.TrackedJob + .REQUIRED_NETWORK); + } + proto.end(jsToken); } - proto.end(jsToken); } proto.end(mToken); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 348b8e69ab96..93b83ae72cca 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3622,7 +3622,7 @@ public class NotificationManagerService extends SystemService { INotificationListener token, String pkg, UserHandle user, NotificationChannelGroup group) throws RemoteException { Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, false); createNotificationChannelGroup( pkg, getUidForPackageAndUser(pkg, user), group, false, true); savePolicyFile(); @@ -3635,7 +3635,7 @@ public class NotificationManagerService extends SystemService { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, false); updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); } @@ -3644,7 +3644,7 @@ public class NotificationManagerService extends SystemService { INotificationListener token, String pkg, UserHandle user) throws RemoteException { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, true); return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), false /* includeDeleted */); @@ -3656,7 +3656,7 @@ public class NotificationManagerService extends SystemService { INotificationListener token, String pkg, UserHandle user) throws RemoteException { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(user); - verifyPrivilegedListener(token, user); + verifyPrivilegedListener(token, user, true); List<NotificationChannelGroup> groups = new ArrayList<>(); groups.addAll(mPreferencesHelper.getNotificationChannelGroups( @@ -3664,13 +3664,18 @@ public class NotificationManagerService extends SystemService { return new ParceledListSlice<>(groups); } - private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { + private void verifyPrivilegedListener(INotificationListener token, UserHandle user, + boolean assistantAllowed) { ManagedServiceInfo info; synchronized (mNotificationLock) { info = mListeners.checkServiceTokenLocked(token); } if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); + synchronized (mNotificationLock) { + if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) { + throw new SecurityException(info + " does not have access"); + } + } } if (!info.enabledAndUserMatches(user.getIdentifier())) { throw new SecurityException(info + " does not have access"); diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 19a62d91dbf7..e9f2718fe2b3 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -753,10 +753,10 @@ public final class NotificationRecord { protected void calculateImportance() { mImportance = calculateInitialImportance(); mImportanceExplanation = "app"; - if (getChannel().isImportanceLocked()) { + if (getChannel().hasUserSetImportance()) { mImportanceExplanation = "user"; } - if (!getChannel().isImportanceLocked() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) { + if (!getChannel().hasUserSetImportance() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) { mImportance = mAssistantImportance; mImportanceExplanation = "asst"; } 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/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index be24c7125969..5569822300b9 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -243,7 +243,7 @@ public class BatterySaverController implements BatterySaverPolicyListener { } /** - * Called by {@link PowerManagerService} to update the battery saver stete. + * Called by {@link PowerManagerService} to update the battery saver state. */ public void enableBatterySaver(boolean enable, int reason) { synchronized (mLock) { @@ -290,8 +290,8 @@ public class BatterySaverController implements BatterySaverPolicyListener { * This method is called only in the following cases: * - When battery saver becomes activated. * - When battery saver becomes deactivated. - * - When battery saver is on the interactive state changes. - * - When battery saver is on the battery saver policy changes. + * - When battery saver is on and the interactive state changes. + * - When battery saver is on and the battery saver policy changes. */ void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) { final LowPowerModeListener[] listeners; diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 6db7e4f1a800..c162afbf3e61 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -88,7 +88,6 @@ import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; import com.android.internal.os.LooperStats; import com.android.internal.os.PowerProfile; -import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.StoragedUidIoStatsReader; import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; @@ -195,8 +194,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static IThermalService sThermalService; private File mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_companion"); - @GuardedBy("this") - ProcessCpuTracker mProcessCpuTracker = null; public StatsCompanionService(Context context) { super(); @@ -1423,34 +1420,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { }); } - private void pullProcessCpuTime(int tagId, long elapsedNanos, final long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - synchronized (this) { - if (mProcessCpuTracker == null) { - mProcessCpuTracker = new ProcessCpuTracker(false); - mProcessCpuTracker.init(); - } - mProcessCpuTracker.update(); - for (int i = 0; i < mProcessCpuTracker.countStats(); i++) { - ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeInt(st.uid); - e.writeString(st.name); - e.writeLong(st.base_utime); - e.writeLong(st.base_stime); - pulledData.add(e); - } - } - } - /** * Pulls various data. */ @Override // Binder call public StatsLogEventWrapper[] pullData(int tagId) { enforceCallingPermission(); - if (DEBUG) { Slog.d(TAG, "Pulling " + tagId); } @@ -1563,8 +1538,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } case StatsLog.PROC_STATS: { - pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, - ret); + pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, ret); break; } case StatsLog.PROC_STATS_PKG_PROC: { @@ -1580,10 +1554,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret); break; } - case StatsLog.PROCESS_CPU_TIME: { - pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret); - break; - } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/core/java/com/android/server/wm/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/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/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index de3d285cd23a..877c8fad3086 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -58,6 +58,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.annotations.GuardedBy; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -67,8 +69,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoSession; -import javax.annotation.concurrent.GuardedBy; - @SmallTest @RunWith(AndroidJUnit4.class) public class AlarmManagerServiceTest { 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/ActivityDisplayTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java index ea90ffd0792f..0da574239666 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java @@ -20,11 +20,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; import android.platform.test.annotations.Presubmit; @@ -131,4 +134,57 @@ public class ActivityDisplayTests extends ActivityTestsBase { new ActivityBuilder(mService).setTask(fullscreenTask).build(); return fullscreenStack; } + + /** + * Verifies the correct activity is returned when querying the top running activity. + */ + @Test + public void testTopRunningActivity() { + // Create stack to hold focus. + final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + final ActivityStack emptyStack = display.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, true /* onTop */); + + final KeyguardController keyguard = mSupervisor.getKeyguardController(); + final ActivityStack stack = mSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + + // Make sure the top running activity is not affected when keyguard is not locked. + assertTopRunningActivity(activity, display); + + // Check to make sure activity not reported when it cannot show on lock and lock is on. + doReturn(true).when(keyguard).isKeyguardLocked(); + assertEquals(activity, display.topRunningActivity()); + assertNull(display.topRunningActivity(true /* considerKeyguardState */)); + + // Change focus to stack with activity. + stack.moveToFront("focusChangeToTestStack"); + assertEquals(stack, display.getFocusedStack()); + assertEquals(activity, display.topRunningActivity()); + assertNull(display.topRunningActivity(true /* considerKeyguardState */)); + + // Add activity that should be shown on the keyguard. + final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService) + .setCreateTask(true) + .setStack(stack) + .setActivityFlags(FLAG_SHOW_WHEN_LOCKED) + .build(); + + // Ensure the show when locked activity is returned. + assertTopRunningActivity(showWhenLockedActivity, display); + + // Change focus back to empty stack. + emptyStack.moveToFront("focusChangeToEmptyStack"); + assertEquals(emptyStack, display.getFocusedStack()); + // If there is no running activity in focused stack, the running activity in next focusable + // stack should be returned. + assertTopRunningActivity(showWhenLockedActivity, display); + } + + private static void assertTopRunningActivity(ActivityRecord top, ActivityDisplay display) { + assertEquals(top, display.topRunningActivity()); + assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */)); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index cc7a24d5700e..2c993d32c20c 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -25,7 +25,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; -import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; @@ -307,62 +306,6 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { } /** - * Verifies the correct activity is returned when querying the top running activity. - */ - @Test - public void testTopRunningActivity() throws Exception { - // Create stack to hold focus - final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay(); - final ActivityStack emptyStack = display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, true /* onTop */); - - final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(stack).build(); - - // Make sure the top running activity is not affected when keyguard is not locked - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Check to make sure activity not reported when it cannot show on lock and lock is on. - doReturn(true).when(keyguard).isKeyguardLocked(); - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Change focus to stack with activity. - stack.moveToFront("focusChangeToTestStack"); - assertEquals(stack, display.getFocusedStack()); - assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Add activity that should be shown on the keyguard. - final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService) - .setCreateTask(true) - .setStack(stack) - .setActivityFlags(FLAG_SHOW_WHEN_LOCKED) - .build(); - - // Ensure the show when locked activity is returned. - assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - - // Change focus back to empty stack - emptyStack.moveToFront("focusChangeToEmptyStack"); - assertEquals(emptyStack, display.getFocusedStack()); - // Looking for running activity only in top and focused stack, so nothing should be returned - // from empty stack. - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked()); - assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( - true /* considerKeyguardState */)); - } - - /** * Verify that split-screen primary stack will be chosen if activity is launched that targets * split-screen secondary, but a matching existing instance is found on top of split-screen * primary stack. diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 5fcd2aa35e05..53f67afb629e 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -26,6 +26,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; +import static com.android.server.am.ActivityStack.ActivityState.FINISHING; +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.REMOVE_TASK_MODE_DESTROYING; @@ -35,10 +38,14 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.anyInt; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -655,6 +662,39 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test + public void testFinishCurrentActivity() { + // Create 2 activities on a new display. + final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); + final ActivityStack stack1 = createStackForShouldBeVisibleTest(display, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityStack stack2 = createStackForShouldBeVisibleTest(display, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + + // There is still an activity1 in stack1 so the activity2 should be added to finishing list + // that will be destroyed until idle. + final ActivityRecord activity2 = finishCurrentActivity(stack2); + assertEquals(FINISHING, activity2.getState()); + assertTrue(mSupervisor.mFinishingActivities.contains(activity2)); + + // The display becomes empty. Since there is no next activity to be idle, the activity + // should be destroyed immediately with updating configuration to restore original state. + final ActivityRecord activity1 = finishCurrentActivity(stack1); + assertEquals(DESTROYING, activity1.getState()); + verify(mSupervisor).ensureVisibilityAndConfig(eq(null) /* starting */, + eq(display.mDisplayId), anyBoolean(), anyBoolean()); + } + + private ActivityRecord finishCurrentActivity(ActivityStack stack) { + final ActivityRecord activity = stack.topRunningActivityLocked(); + assertNotNull(activity); + activity.setState(PAUSED, "finishCurrentActivity"); + activity.makeFinishingLocked(); + stack.finishCurrentActivityLocked(activity, ActivityStack.FINISH_AFTER_VISIBLE, + false /* oomAdj */, "finishCurrentActivity"); + return activity; + } + + @Test public void testShouldSleepActivities() throws Exception { // When focused activity and keyguard is going away, we should not sleep regardless // of the display state diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java index bd4a356fcb5c..77f6a23c26b1 100644 --- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java @@ -58,7 +58,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase { + "adjust_brightness_factor=0.7," + "fullbackup_deferred=true," + "keyvaluebackup_deferred=false," - + "gps_mode=0"; + + "gps_mode=0," + + "quick_doze_enabled=true"; private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true"; private class BatterySaverPolicyForTest extends BatterySaverPolicy { @@ -102,48 +103,48 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @SmallTest public void testGetBatterySaverPolicy_PolicyNull_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.NULL); + testServiceDefaultValue_On(ServiceType.NULL); } @SmallTest public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.VIBRATION); + testServiceDefaultValue_On(ServiceType.VIBRATION); } @SmallTest public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() { mBatterySaverPolicy.setAccessibilityEnabledForTest(true); - testServiceDefaultValue_unchanged(ServiceType.VIBRATION); + testServiceDefaultValue_Off(ServiceType.VIBRATION); } @SmallTest public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.SOUND); + testServiceDefaultValue_On(ServiceType.SOUND); } @SmallTest public void testGetBatterySaverPolicy_PolicyFullBackup_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.FULL_BACKUP); + testServiceDefaultValue_On(ServiceType.FULL_BACKUP); } @SmallTest public void testGetBatterySaverPolicy_PolicyKeyValueBackup_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.KEYVALUE_BACKUP); + testServiceDefaultValue_On(ServiceType.KEYVALUE_BACKUP); } @SmallTest public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() { - testServiceDefaultValue_unchanged(ServiceType.ANIMATION); + testServiceDefaultValue_Off(ServiceType.ANIMATION); } @SmallTest public void testGetBatterySaverPolicy_PolicyBatteryStats_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.BATTERY_STATS); + testServiceDefaultValue_On(ServiceType.BATTERY_STATS); } @SmallTest public void testGetBatterySaverPolicy_PolicyNetworkFirewall_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.NETWORK_FIREWALL); + testServiceDefaultValue_On(ServiceType.NETWORK_FIREWALL); } @SmallTest @@ -160,12 +161,12 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @SmallTest public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() { - testServiceDefaultValue_unchanged(ServiceType.SCREEN_BRIGHTNESS); + testServiceDefaultValue_Off(ServiceType.SCREEN_BRIGHTNESS); } @SmallTest public void testGetBatterySaverPolicy_PolicyGps_DefaultValueCorrect() { - testServiceDefaultValue(ServiceType.GPS); + testServiceDefaultValue_On(ServiceType.GPS); PowerSaveState stateOn = mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, true); @@ -173,6 +174,11 @@ public class BatterySaverPolicyTest extends AndroidTestCase { } @SmallTest + public void testGetBatterySaverPolicy_PolicyQuickDoze_DefaultValueCorrect() { + testServiceDefaultValue_Off(ServiceType.QUICK_DOZE); + } + + @SmallTest public void testUpdateConstants_getCorrectData() { mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, ""); @@ -214,6 +220,10 @@ public class BatterySaverPolicyTest extends AndroidTestCase { mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, BATTERY_SAVER_ON); assertThat(gpsState.batterySaverEnabled).isTrue(); assertThat(gpsState.gpsMode).isEqualTo(GPS_MODE); + + final PowerSaveState quickDozeState = mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.QUICK_DOZE, BATTERY_SAVER_ON); + assertThat(quickDozeState.batterySaverEnabled).isTrue(); } @SmallTest @@ -223,7 +233,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { mBatterySaverPolicy.updateConstantsLocked(null, ""); } - private void testServiceDefaultValue(@ServiceType int type) { + private void testServiceDefaultValue_On(@ServiceType int type) { mBatterySaverPolicy.updateConstantsLocked("", ""); final PowerSaveState batterySaverStateOn = mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON); @@ -234,7 +244,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertThat(batterySaverStateOff.batterySaverEnabled).isFalse(); } - private void testServiceDefaultValue_unchanged(@ServiceType int type) { + private void testServiceDefaultValue_Off(@ServiceType int type) { mBatterySaverPolicy.updateConstantsLocked("", ""); final PowerSaveState batterySaverStateOn = mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON); diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 869f8fa0c2fa..caaa0bbe6c60 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -43,6 +43,7 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import android.app.usage.AppStandbyInfo; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; @@ -92,6 +93,8 @@ public class AppStandbyControllerTests { private static final int USER_ID = 0; private static final int USER_ID2 = 10; + private static final String PACKAGE_UNKNOWN = "com.example.unknown"; + private static final String ADMIN_PKG = "com.android.admin"; private static final String ADMIN_PKG2 = "com.android.admin2"; private static final String ADMIN_PKG3 = "com.android.admin3"; @@ -106,6 +109,9 @@ public class AppStandbyControllerTests { // Short STABLE_CHARGING_THRESHOLD for testing purposes private static final long STABLE_CHARGING_THRESHOLD = 2000; + /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */ + private static boolean isPackageInstalled = true; + private MyInjector mInjector; private AppStandbyController mController; @@ -183,6 +189,12 @@ public class AppStandbyControllerTests { } @Override + boolean isPackageInstalled(String packageName, int flags, int userId) { + // Should always return true (default value) unless testing for an uninstalled app + return isPackageInstalled; + } + + @Override int[] getRunningUserIds() { return new int[] {USER_ID}; } @@ -403,30 +415,30 @@ public class AppStandbyControllerTests { false)); } - private void reportEvent(AppStandbyController controller, int eventType, - long elapsedTime) { + private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime, + String packageName) { // Back to ACTIVE on event mInjector.mElapsedRealtime = elapsedTime; UsageEvents.Event ev = new UsageEvents.Event(); - ev.mPackage = PACKAGE_1; + ev.mPackage = packageName; ev.mEventType = eventType; controller.reportEvent(ev, elapsedTime, USER_ID); } - private int getStandbyBucket(AppStandbyController controller) { - return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, + private int getStandbyBucket(AppStandbyController controller, String packageName) { + return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime, true); } private void assertBucket(int bucket) { - assertEquals(bucket, getStandbyBucket(mController)); + assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testBuckets() throws Exception { assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); // ACTIVE bucket assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); @@ -443,7 +455,7 @@ public class AppStandbyControllerTests { // RARE bucket assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); - reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1); + reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1); assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); @@ -452,12 +464,48 @@ public class AppStandbyControllerTests { } @Test + public void testSetAppStandbyBucket() throws Exception { + // For a known package, standby bucket should be set properly + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_MAIN_TIMEOUT, HOUR_MS); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); + + // For an unknown package, standby bucket should not be set, hence NEVER is returned + // Ensure the unknown package is not already in history by removing it + mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID); + isPackageInstalled = false; // Mock package is not installed + mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_MAIN_TIMEOUT, HOUR_MS); + isPackageInstalled = true; // Reset mocked variable for other tests + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN)); + } + + @Test + public void testAppStandbyBucketOnInstallAndUninstall() throws Exception { + // On package install, standby bucket should be ACTIVE + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_UNKNOWN)); + + // On uninstall, package should not exist in history and should return a NEVER bucket + mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID); + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN)); + // Ensure uninstalled app is not in history + List<AppStandbyInfo> buckets = mController.getAppStandbyBuckets(USER_ID); + for(AppStandbyInfo bucket : buckets) { + if (bucket.mPackageName.equals(PACKAGE_UNKNOWN)) { + fail("packageName found in app idle history after uninstall."); + } + } + } + + @Test public void testScreenTimeAndBuckets() throws Exception { mInjector.setDisplayOn(false); assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); // ACTIVE bucket assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); @@ -468,7 +516,7 @@ public class AppStandbyControllerTests { // RARE bucket, should fail because the screen wasn't ON. mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; mController.checkIdleStates(USER_ID); - assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); mInjector.setDisplayOn(true); assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); @@ -477,7 +525,7 @@ public class AppStandbyControllerTests { @Test public void testForcedIdle() throws Exception { mController.forceIdleState(PACKAGE_1, USER_ID, true); - assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); mController.forceIdleState(PACKAGE_1, USER_ID, false); @@ -488,35 +536,35 @@ public class AppStandbyControllerTests { @Test public void testNotificationEvent() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mInjector.mElapsedRealtime = 1; - reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mController.forceIdleState(PACKAGE_1, USER_ID, true); - reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); + reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testSlicePinnedEvent() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mInjector.mElapsedRealtime = 1; - reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); mController.forceIdleState(PACKAGE_1, USER_ID, true); - reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); + reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testSlicePinnedPrivEvent() throws Exception { mController.forceIdleState(PACKAGE_1, USER_ID, true); - reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } @Test @@ -524,28 +572,28 @@ public class AppStandbyControllerTests { // Set it to timeout or usage, so that prediction can override it mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_TIMEOUT, HOUR_MS); - assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_MAIN_PREDICTED, HOUR_MS); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); // Fast forward 12 hours mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD; mController.checkIdleStates(USER_ID); // Should still be in predicted bucket, since prediction timeout is 1 day since prediction - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); // Fast forward two more hours mInjector.mElapsedRealtime += 2 * HOUR_MS; mController.checkIdleStates(USER_ID); // Should have now applied prediction timeout - assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); // Fast forward RARE bucket mInjector.mElapsedRealtime += RARE_THRESHOLD; mController.checkIdleStates(USER_ID); // Should continue to apply prediction timeout - assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); } @Test @@ -553,33 +601,33 @@ public class AppStandbyControllerTests { // Can force to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_FORCED, 1 * HOUR_MS); - assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); // Prediction can't override FORCED reason mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, REASON_MAIN_FORCED, 1 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, REASON_MAIN_PREDICTED, 1 * HOUR_MS); - assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1)); // Prediction can't override NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_DEFAULT, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_MAIN_PREDICTED, 2 * HOUR_MS); - assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); // Prediction can't set to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_MAIN_USAGE, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_PREDICTED, 2 * HOUR_MS); - assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); + assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } @Test public void testTimeout() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mInjector.mElapsedRealtime = 2000; @@ -601,10 +649,10 @@ public class AppStandbyControllerTests { @Test public void testCascadingTimeouts() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); - reportEvent(mController, NOTIFICATION_SEEN, 1000); + reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, @@ -622,14 +670,15 @@ public class AppStandbyControllerTests { @Test public void testOverlappingTimeouts() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); - reportEvent(mController, NOTIFICATION_SEEN, 1000); + reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Overlapping USER_INTERACTION before previous one times out - reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000); + reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000, + PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Still in ACTIVE after first USER_INTERACTION times out @@ -654,14 +703,14 @@ public class AppStandbyControllerTests { public void testSystemInteractionTimeout() throws Exception { setChargingState(mController, false); - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); // Fast forward to RARE mInjector.mElapsedRealtime = RARE_THRESHOLD + 100; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_RARE); // Trigger a SYSTEM_INTERACTION and verify bucket - reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime); + reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Verify it's still in ACTIVE close to end of timeout @@ -677,11 +726,11 @@ public class AppStandbyControllerTests { @Test public void testPredictionNotOverridden() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000; - reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); + reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Falls back to WORKING_SET @@ -703,7 +752,7 @@ public class AppStandbyControllerTests { @Test public void testPredictionStrikesBack() throws Exception { - reportEvent(mController, USER_INTERACTION, 0); + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); // Predict to FREQUENT @@ -714,7 +763,7 @@ public class AppStandbyControllerTests { // Add a short timeout event mInjector.mElapsedRealtime += 1000; - reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime); + reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); mInjector.mElapsedRealtime += 1000; mController.checkIdleStates(USER_ID); 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/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 4e007c2d9929..3266b8b92a19 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -1689,7 +1689,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testGetNotificationChannelFromPrivilegedListener_success() throws Exception { + public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); List<String> associations = new ArrayList<>(); associations.add("a"); @@ -1703,7 +1703,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception { + public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); List<String> associations = new ArrayList<>(); when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); @@ -1721,6 +1721,38 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testGetNotificationChannelFromPrivilegedListener_assistant_success() + throws Exception { + mService.setPreferencesHelper(mPreferencesHelper); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>()); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + + verify(mPreferencesHelper, times(1)).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + + @Test + public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception { + mService.setPreferencesHelper(mPreferencesHelper); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>()); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); + + try { + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listeners that don't have a companion device shouldn't be able to call this"); + } catch (SecurityException e) { + // pass + } + + verify(mPreferencesHelper, never()).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + + @Test public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); List<String> associations = new ArrayList<>(); 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/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java index 4e997323a30e..bc54a5d2c499 100644 --- a/services/usage/java/com/android/server/usage/AppIdleHistory.java +++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java @@ -320,14 +320,7 @@ public class AppIdleHistory { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); - if (appUsageHistory == null) { - return false; // Default to not idle - } else { - return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE; - // Whether or not it's passed will now be externally calculated and the - // bucket will be pushed to the history using setAppStandbyBucket() - //return hasPassedThresholds(appUsageHistory, elapsedRealtime); - } + return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE; } public AppUsageHistory getAppUsageHistory(String packageName, int userId, @@ -404,17 +397,19 @@ public class AppIdleHistory { public long getTimeSinceLastJobRun(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = - getPackageHistory(userHistory, packageName, elapsedRealtime, true); + getPackageHistory(userHistory, packageName, elapsedRealtime, false); // Don't adjust the default, else it'll wrap around to a positive value - if (appUsageHistory.lastJobRunTime == Long.MIN_VALUE) return Long.MAX_VALUE; + if (appUsageHistory == null || appUsageHistory.lastJobRunTime == Long.MIN_VALUE) { + return Long.MAX_VALUE; + } return getElapsedTime(elapsedRealtime) - appUsageHistory.lastJobRunTime; } public int getAppStandbyBucket(String packageName, int userId, long elapsedRealtime) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = - getPackageHistory(userHistory, packageName, elapsedRealtime, true); - return appUsageHistory.currentBucket; + getPackageHistory(userHistory, packageName, elapsedRealtime, false); + return appUsageHistory == null ? STANDBY_BUCKET_NEVER : appUsageHistory.currentBucket; } public ArrayList<AppStandbyInfo> getAppStandbyBuckets(int userId, boolean appIdleEnabled) { diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 02ad3a8772f8..6a74564367b8 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -1161,6 +1161,10 @@ public class AppStandbyController { void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout) { synchronized (mAppIdleLock) { + // If the package is not installed, don't allow the bucket to be set. + if (!mInjector.isPackageInstalled(packageName, 0, userId)) { + return; + } AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED; @@ -1594,6 +1598,10 @@ public class AppStandbyController { return mPackageManagerInternal.isPackageEphemeral(userId, packageName); } + boolean isPackageInstalled(String packageName, int flags, int userId) { + return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0; + } + int[] getRunningUserIds() throws RemoteException { return ActivityManager.getService().getRunningUserIds(); } 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(); } |