Merge "Log the elapsed realtime in non-chained interface."
diff --git a/Android.bp b/Android.bp
index 03abf75..e65ba0f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -249,8 +249,7 @@
"core/java/android/os/storage/IStorageEventListener.aidl",
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
- "core/java/android/security/IConfirmationPromptCallback.aidl",
- "core/java/android/security/IKeystoreService.aidl",
+ ":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
"core/java/android/service/autofill/IAutoFillService.aidl",
"core/java/android/service/autofill/IAutofillFieldClassificationService.aidl",
@@ -643,6 +642,7 @@
"system/netd/server/binder",
"system/vold/binder",
"system/bt/binder",
+ "system/security/keystore/binder",
],
},
diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java
similarity index 73%
rename from apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
rename to apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java
index 73e1724..fc6302e 100644
--- a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
+++ b/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java
@@ -45,7 +45,7 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class PrecomputedTextMemoryUsageTest {
+public class MeasuredTextMemoryUsageTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final boolean NO_STYLE_TEXT = false;
@@ -53,7 +53,7 @@
private static int TRIAL_COUNT = 100;
- public PrecomputedTextMemoryUsageTest() {}
+ public MeasuredTextMemoryUsageTest() {}
private TextPerfUtils mTextUtil = new TextPerfUtils();
@@ -77,16 +77,13 @@
@Test
public void testMemoryUsage_NoHyphenation() {
int[] memories = new int[TRIAL_COUNT];
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
+ // Report median of randomly generated MeasuredText.
+ for (int i = 0; i < TRIAL_COUNT; ++i) {
+ memories[i] = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
- .build();
-
- // Report median of randomly generated PrecomputedText.
- for (int i = 0; i < TRIAL_COUNT; ++i) {
- memories[i] = PrecomputedText.create(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param)
- .getMemoryUsage();
+ .build().getMemoryUsage();
}
reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation");
}
@@ -94,16 +91,13 @@
@Test
public void testMemoryUsage_Hyphenation() {
int[] memories = new int[TRIAL_COUNT];
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
+ // Report median of randomly generated MeasuredText.
+ for (int i = 0; i < TRIAL_COUNT; ++i) {
+ memories[i] = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .build();
-
- // Report median of randomly generated PrecomputedText.
- for (int i = 0; i < TRIAL_COUNT; ++i) {
- memories[i] = PrecomputedText.create(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param)
- .getMemoryUsage();
+ .build().getMemoryUsage();
}
reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation");
}
@@ -111,16 +105,13 @@
@Test
public void testMemoryUsage_NoHyphenation_WidthOnly() {
int[] memories = new int[TRIAL_COUNT];
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
+ // Report median of randomly generated MeasuredText.
+ for (int i = 0; i < TRIAL_COUNT; ++i) {
+ memories[i] = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
- .build();
-
- // Report median of randomly generated PrecomputedText.
- for (int i = 0; i < TRIAL_COUNT; ++i) {
- CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
- memories[i] = PrecomputedText.createWidthOnly(cs, param, 0, cs.length())
- .getMemoryUsage();
+ .build(false /* width only */).getMemoryUsage();
}
reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly");
}
@@ -128,16 +119,13 @@
@Test
public void testMemoryUsage_Hyphenatation_WidthOnly() {
int[] memories = new int[TRIAL_COUNT];
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
+ // Report median of randomly generated MeasuredText.
+ for (int i = 0; i < TRIAL_COUNT; ++i) {
+ memories[i] = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .build();
-
- // Report median of randomly generated PrecomputedText.
- for (int i = 0; i < TRIAL_COUNT; ++i) {
- CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
- memories[i] = PrecomputedText.createWidthOnly(cs, param, 0, cs.length())
- .getMemoryUsage();
+ .build(false /* width only */).getMemoryUsage();
}
reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly");
}
diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java
similarity index 66%
rename from apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
rename to apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java
index 1cd0ae1..98f2bd5 100644
--- a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java
@@ -42,7 +42,7 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class PrecomputedTextPerfTest {
+public class MeasuredTextPerfTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
private static final boolean NO_STYLE_TEXT = false;
@@ -51,7 +51,7 @@
private static TextPaint PAINT = new TextPaint();
private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
- public PrecomputedTextPerfTest() {}
+ public MeasuredTextPerfTest() {}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@@ -66,136 +66,120 @@
@Test
public void testCreate_NoStyled_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build(true /* do full layout */);
}
}
@Test
public void testCreate_NoStyled_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build(true /* do full layout */);
}
}
@Test
public void testCreate_NoStyled_Hyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build(false /* width only */);
}
}
@Test
public void testCreate_NoStyled_NoHyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build(false /* width only */);
}
}
@Test
public void testCreate_Styled_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build(true /* do full layout */);
}
}
@Test
public void testCreate_Styled_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build(true /* do full layout */);
}
}
@Test
public void testCreate_Styled_Hyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build(false /* width only */);
}
}
@Test
public void testCreate_Styled_NoHyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
- .build();
-
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
- PrecomputedText.create(text, param);
+ new MeasuredText.Builder(text, PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build(false /* width only */);
}
}
}
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 8823af1..231aaf2 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -63,18 +63,6 @@
mTextUtil.resetRandom(0 /* seed */);
}
- private PrecomputedText makeMeasured(CharSequence text, TextPaint paint) {
- PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint).build();
- return PrecomputedText.create(text, param);
- }
-
- private PrecomputedText makeMeasured(CharSequence text, TextPaint paint, int strategy,
- int frequency) {
- PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
- .setHyphenationFrequency(frequency).setBreakStrategy(strategy).build();
- return PrecomputedText.create(text, param);
- }
-
@Test
public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -163,16 +151,18 @@
}
@Test
- public void testCreate_PrecomputedText_NoStyled_Greedy_NoHyphenation() {
+ public void testCreate_MeasuredText_NoStyled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
- Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build();
state.resumeTiming();
- StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH)
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
@@ -180,16 +170,18 @@
}
@Test
- public void testCreate_PrecomputedText_NoStyled_Greedy_Hyphenation() {
+ public void testCreate_MeasuredText_NoStyled_Greedy_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
- Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NORMAL);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build();
state.resumeTiming();
- StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH)
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
@@ -197,16 +189,18 @@
}
@Test
- public void testCreate_PrecomputedText_NoStyled_Balanced_NoHyphenation() {
+ public void testCreate_MeasuredText_NoStyled_Balanced_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
- Layout.BREAK_STRATEGY_BALANCED, Layout.HYPHENATION_FREQUENCY_NONE);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build();
state.resumeTiming();
- StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH)
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
@@ -214,16 +208,18 @@
}
@Test
- public void testCreate_PrecomputedText_NoStyled_Balanced_Hyphenation() {
+ public void testCreate_MeasuredText_NoStyled_Balanced_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
- Layout.BREAK_STRATEGY_BALANCED, Layout.HYPHENATION_FREQUENCY_NORMAL);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build();
state.resumeTiming();
- StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH)
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
@@ -231,16 +227,18 @@
}
@Test
- public void testCreate_PrecomputedText_Styled_Greedy_NoHyphenation() {
+ public void testCreate_MeasuredText_Styled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT,
- Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .build();
state.resumeTiming();
- StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH)
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
@@ -330,16 +328,15 @@
}
@Test
- public void testDraw_PrecomputedText_Styled() {
+ public void testDraw_MeasuredText_Styled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
final StaticLayout layout =
- StaticLayout.Builder.obtain(
- text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build();
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
@@ -348,16 +345,15 @@
}
@Test
- public void testDraw_PrecomputedText_NoStyled() {
+ public void testDraw_MeasuredText_NoStyled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
final StaticLayout layout =
- StaticLayout.Builder.obtain(
- text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build();
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
@@ -366,16 +362,15 @@
}
@Test
- public void testDraw_PrecomputedText_Styled_WithoutCache() {
+ public void testDraw_MeasuredText_Styled_WithoutCache() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
final StaticLayout layout =
- StaticLayout.Builder.obtain(
- text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build();
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
@@ -385,16 +380,15 @@
}
@Test
- public void testDraw_PrecomputedText_NoStyled_WithoutCache() {
+ public void testDraw_MeasuredText_NoStyled_WithoutCache() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
- final PrecomputedText text = makeMeasured(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
+ final MeasuredText text = new MeasuredText.Builder(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
final StaticLayout layout =
- StaticLayout.Builder.obtain(
- text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build();
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
diff --git a/api/current.txt b/api/current.txt
index 042360e..3963f3a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1468,6 +1468,7 @@
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
+ field public static final int urlBarResourceId = 16844164; // 0x1010584
field public static final int use32bitAbi = 16844053; // 0x1010515
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
@@ -12554,6 +12555,7 @@
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void setIdleConnectionTimeout(long);
method public void setLookasideConfig(int, int);
+ method public void setOpenParams(android.database.sqlite.SQLiteDatabase.OpenParams);
method public void setWriteAheadLoggingEnabled(boolean);
}
@@ -13837,7 +13839,6 @@
method public int breakText(java.lang.String, boolean, float, float[]);
method public void clearShadowLayer();
method public float descent();
- method public boolean equalsForTextMeasurement(android.graphics.Paint);
method public int getAlpha();
method public int getColor();
method public android.graphics.ColorFilter getColorFilter();
@@ -38683,14 +38684,14 @@
}
public final class DateTransformation implements android.os.Parcelable android.service.autofill.Transformation {
- ctor public DateTransformation(android.view.autofill.AutofillId, java.text.DateFormat);
+ ctor public DateTransformation(android.view.autofill.AutofillId, android.icu.text.DateFormat);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.DateTransformation> CREATOR;
}
public final class DateValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
- ctor public DateValueSanitizer(java.text.DateFormat);
+ ctor public DateValueSanitizer(android.icu.text.DateFormat);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.DateValueSanitizer> CREATOR;
@@ -43227,6 +43228,36 @@
method public boolean isAllowed(char);
}
+ public class MeasuredText implements android.text.Spanned {
+ method public char charAt(int);
+ method public int getBreakStrategy();
+ method public int getEnd();
+ method public int getHyphenationFrequency();
+ method public android.text.TextPaint getPaint();
+ method public int getParagraphCount();
+ method public int getParagraphEnd(int);
+ method public int getParagraphStart(int);
+ method public int getSpanEnd(java.lang.Object);
+ method public int getSpanFlags(java.lang.Object);
+ method public int getSpanStart(java.lang.Object);
+ method public <T> T[] getSpans(int, int, java.lang.Class<T>);
+ method public int getStart();
+ method public java.lang.CharSequence getText();
+ method public android.text.TextDirectionHeuristic getTextDir();
+ method public int length();
+ method public int nextSpanTransition(int, int, java.lang.Class);
+ method public java.lang.CharSequence subSequence(int, int);
+ }
+
+ public static final class MeasuredText.Builder {
+ ctor public MeasuredText.Builder(java.lang.CharSequence, android.text.TextPaint);
+ method public android.text.MeasuredText build();
+ method public android.text.MeasuredText.Builder setBreakStrategy(int);
+ method public android.text.MeasuredText.Builder setHyphenationFrequency(int);
+ method public android.text.MeasuredText.Builder setRange(int, int);
+ method public android.text.MeasuredText.Builder setTextDirection(android.text.TextDirectionHeuristic);
+ }
+
public abstract interface NoCopySpan {
}
@@ -43238,31 +43269,6 @@
method public abstract int getSpanTypeId();
}
- public class PrecomputedText {
- method public static android.text.PrecomputedText create(java.lang.CharSequence, android.text.PrecomputedText.Params);
- method public int getParagraphCount();
- method public int getParagraphEnd(int);
- method public int getParagraphStart(int);
- method public android.text.PrecomputedText.Params getParams();
- method public java.lang.CharSequence getText();
- }
-
- public static class PrecomputedText.Params {
- method public int getBreakStrategy();
- method public int getHyphenationFrequency();
- method public android.text.TextDirectionHeuristic getTextDirection();
- method public android.text.TextPaint getTextPaint();
- method public boolean sameTextMetrics(android.text.PrecomputedText.Params);
- }
-
- public static class PrecomputedText.Params.Builder {
- ctor public PrecomputedText.Params.Builder(android.text.TextPaint);
- method public android.text.PrecomputedText.Params build();
- method public android.text.PrecomputedText.Params.Builder setBreakStrategy(int);
- method public android.text.PrecomputedText.Params.Builder setHyphenationFrequency(int);
- method public android.text.PrecomputedText.Params.Builder setTextDirection(android.text.TextDirectionHeuristic);
- }
-
public class Selection {
method public static boolean extendDown(android.text.Spannable, android.text.Layout);
method public static boolean extendLeft(android.text.Spannable, android.text.Layout);
@@ -43394,7 +43400,6 @@
public static final class StaticLayout.Builder {
method public android.text.StaticLayout build();
- method public static android.text.StaticLayout.Builder obtain(android.text.PrecomputedText, int, int, android.text.TextPaint, int);
method public static android.text.StaticLayout.Builder obtain(java.lang.CharSequence, int, int, android.text.TextPaint, int);
method public android.text.StaticLayout.Builder setAlignment(android.text.Layout.Alignment);
method public android.text.StaticLayout.Builder setBreakStrategy(int);
@@ -53646,7 +53651,6 @@
method public final android.content.res.ColorStateList getTextColors();
method public java.util.Locale getTextLocale();
method public android.os.LocaleList getTextLocales();
- method public android.text.PrecomputedText.Params getTextMetricsParams();
method public float getTextScaleX();
method public float getTextSize();
method public int getTotalPaddingBottom();
@@ -53752,8 +53756,6 @@
method public final void setMovementMethod(android.text.method.MovementMethod);
method public void setOnEditorActionListener(android.widget.TextView.OnEditorActionListener);
method public void setPaintFlags(int);
- method public void setPrecomputedTextAndParams(android.text.PrecomputedText);
- method public void setPrecomputedTextOrThrow(android.text.PrecomputedText);
method public void setPrivateImeOptions(java.lang.String);
method public void setRawInputType(int);
method public void setScroller(android.widget.Scroller);
@@ -53778,7 +53780,6 @@
method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
method public void setTextLocale(java.util.Locale);
method public void setTextLocales(android.os.LocaleList);
- method public void setTextMetricsParams(android.text.PrecomputedText.Params);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSize(int, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 39cbe90..5afb455 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -229,7 +229,6 @@
method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
method public deprecated boolean isBackgroundVisibleBehind();
method public deprecated void onBackgroundVisibleBehindChanged(boolean);
- method public void setDisablePreviewScreenshots(boolean);
}
public static abstract interface Activity.TranslucentConversionListener {
@@ -3606,11 +3605,14 @@
}
public abstract class HwBinder implements android.os.IHwBinder {
+ ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
method public static void enableInstrumentation();
method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException;
method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
method public static final void joinRpcThreadpool();
+ method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+ method public final void registerService(java.lang.String) throws android.os.RemoteException;
method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index b02da04..eda6296 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1047,6 +1047,15 @@
}
+package android.view.animation {
+
+ public class AnimationUtils {
+ method public static void lockAnimationClock(long);
+ method public static void unlockAnimationClock();
+ }
+
+}
+
package android.view.autofill {
public final class AutofillId implements android.os.Parcelable {
diff --git a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
index 02f1ce7..fde17bd 100644
--- a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
@@ -62,15 +62,15 @@
ProtoOutputStream proto;
long jiffyHz = sysconf(_SC_CLK_TCK);
- proto.write(CpuFreq::JIFFY_HZ, (int)jiffyHz);
+ proto.write(CpuFreqProto::JIFFY_HZ, (int)jiffyHz);
for (int i=0; i<numCpus; i++) {
- long long token = proto.start(CpuFreq::CPU_FREQS);
- proto.write(CpuFreqStats::CPU_NAME, header[i+1]);
+ long long token = proto.start(CpuFreqProto::CPU_FREQS);
+ proto.write(CpuFreqProto::Stats::CPU_NAME, header[i+1]);
for (vector<pair<int, long long>>::iterator it = cpucores[i].begin(); it != cpucores[i].end(); it++) {
- long long stateToken = proto.start(CpuFreqStats::TIMES);
- proto.write(CpuFreqStats::TimeInState::STATE_KHZ, it->first);
- proto.write(CpuFreqStats::TimeInState::TIME_JIFFY, it->second);
+ long long stateToken = proto.start(CpuFreqProto::Stats::TIMES);
+ proto.write(CpuFreqProto::Stats::TimeInState::STATE_KHZ, it->first);
+ proto.write(CpuFreqProto::Stats::TimeInState::TIME_JIFFY, it->second);
proto.end(stateToken);
}
proto.end(token);
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
index d73de54..b2b431c 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -54,11 +54,11 @@
bool nextToUsage = false;
ProtoOutputStream proto;
- Table table(CpuInfo::Task::_FIELD_NAMES, CpuInfo::Task::_FIELD_IDS, CpuInfo::Task::_FIELD_COUNT);
- table.addEnumTypeMap("s", CpuInfo::Task::_ENUM_STATUS_NAMES,
- CpuInfo::Task::_ENUM_STATUS_VALUES, CpuInfo::Task::_ENUM_STATUS_COUNT);
- table.addEnumTypeMap("pcy", CpuInfo::Task::_ENUM_POLICY_NAMES,
- CpuInfo::Task::_ENUM_POLICY_VALUES, CpuInfo::Task::_ENUM_POLICY_COUNT);
+ Table table(CpuInfoProto::Task::_FIELD_NAMES, CpuInfoProto::Task::_FIELD_IDS, CpuInfoProto::Task::_FIELD_COUNT);
+ table.addEnumTypeMap("s", CpuInfoProto::Task::_ENUM_STATUS_NAMES,
+ CpuInfoProto::Task::_ENUM_STATUS_VALUES, CpuInfoProto::Task::_ENUM_STATUS_COUNT);
+ table.addEnumTypeMap("pcy", CpuInfoProto::Task::_ENUM_POLICY_NAMES,
+ CpuInfoProto::Task::_ENUM_POLICY_VALUES, CpuInfoProto::Task::_ENUM_POLICY_COUNT);
// parse line by line
while (reader.readLine(&line)) {
@@ -67,33 +67,33 @@
nline++;
if (stripPrefix(&line, "Tasks:")) {
- writeSuffixLine(&proto, CpuInfo::TASK_STATS, line, COMMA_DELIMITER,
- CpuInfo::TaskStats::_FIELD_COUNT,
- CpuInfo::TaskStats::_FIELD_NAMES,
- CpuInfo::TaskStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::TASK_STATS, line, COMMA_DELIMITER,
+ CpuInfoProto::TaskStats::_FIELD_COUNT,
+ CpuInfoProto::TaskStats::_FIELD_NAMES,
+ CpuInfoProto::TaskStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Mem:")) {
- writeSuffixLine(&proto, CpuInfo::MEM, line, COMMA_DELIMITER,
- CpuInfo::MemStats::_FIELD_COUNT,
- CpuInfo::MemStats::_FIELD_NAMES,
- CpuInfo::MemStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::MEM, line, COMMA_DELIMITER,
+ CpuInfoProto::MemStats::_FIELD_COUNT,
+ CpuInfoProto::MemStats::_FIELD_NAMES,
+ CpuInfoProto::MemStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Swap:")) {
- writeSuffixLine(&proto, CpuInfo::SWAP, line, COMMA_DELIMITER,
- CpuInfo::MemStats::_FIELD_COUNT,
- CpuInfo::MemStats::_FIELD_NAMES,
- CpuInfo::MemStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::SWAP, line, COMMA_DELIMITER,
+ CpuInfoProto::MemStats::_FIELD_COUNT,
+ CpuInfoProto::MemStats::_FIELD_NAMES,
+ CpuInfoProto::MemStats::_FIELD_IDS);
nextToSwap = true;
continue;
}
if (nextToSwap) {
- writeSuffixLine(&proto, CpuInfo::CPU_USAGE, line, DEFAULT_WHITESPACE,
- CpuInfo::CpuUsage::_FIELD_COUNT,
- CpuInfo::CpuUsage::_FIELD_NAMES,
- CpuInfo::CpuUsage::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::CPU_USAGE, line, DEFAULT_WHITESPACE,
+ CpuInfoProto::CpuUsage::_FIELD_COUNT,
+ CpuInfoProto::CpuUsage::_FIELD_NAMES,
+ CpuInfoProto::CpuUsage::_FIELD_IDS);
nextToUsage = true;
nextToSwap = false;
continue;
@@ -138,7 +138,7 @@
continue;
}
- long long token = proto.start(CpuInfo::TASKS);
+ long long token = proto.start(CpuInfoProto::TASKS);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d fails to insert field %s with value %s\n",
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index cae51ab..28816ea 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -33,7 +33,9 @@
int nline = 0;
ProtoOutputStream proto;
- Table table(WakeupSourceProto::_FIELD_NAMES, WakeupSourceProto::_FIELD_IDS, WakeupSourceProto::_FIELD_COUNT);
+ Table table(KernelWakeSourcesProto::WakeupSource::_FIELD_NAMES,
+ KernelWakeSourcesProto::WakeupSource::_FIELD_IDS,
+ KernelWakeSourcesProto::WakeupSource::_FIELD_COUNT);
// parse line by line
while (reader.readLine(&line)) {
@@ -57,7 +59,7 @@
continue;
}
- long long token = proto.start(KernelWakeSources::WAKEUP_SOURCES);
+ long long token = proto.start(KernelWakeSourcesProto::WAKEUP_SOURCES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
index f1b93ff..45a0e7b 100644
--- a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -33,7 +33,9 @@
header_t blockHeader;
ProtoOutputStream proto;
- Table table(BlockProto::_FIELD_NAMES, BlockProto::_FIELD_IDS, BlockProto::_FIELD_COUNT);
+ Table table(PageTypeInfoProto::Block::_FIELD_NAMES,
+ PageTypeInfoProto::Block::_FIELD_IDS,
+ PageTypeInfoProto::Block::_FIELD_COUNT);
while (reader.readLine(&line)) {
if (line.empty()) {
@@ -44,11 +46,11 @@
if (stripPrefix(&line, "Page block order:")) {
pageBlockOrder = toInt(line);
- proto.write(PageTypeInfo::PAGE_BLOCK_ORDER, pageBlockOrder);
+ proto.write(PageTypeInfoProto::PAGE_BLOCK_ORDER, pageBlockOrder);
continue;
}
if (stripPrefix(&line, "Pages per block:")) {
- proto.write(PageTypeInfo::PAGES_PER_BLOCK, toInt(line));
+ proto.write(PageTypeInfoProto::PAGES_PER_BLOCK, toInt(line));
continue;
}
if (stripPrefix(&line, "Free pages count per migrate type at order")) {
@@ -62,14 +64,14 @@
record_t record = parseRecord(line, COMMA_DELIMITER);
if (migrateTypeSession && record.size() == 3) {
- long long token = proto.start(PageTypeInfo::MIGRATE_TYPES);
+ long long token = proto.start(PageTypeInfoProto::MIGRATE_TYPES);
// expect part 0 starts with "Node"
if (stripPrefix(&record[0], "Node")) {
- proto.write(MigrateTypeProto::NODE, toInt(record[0]));
+ proto.write(PageTypeInfoProto::MigrateType::NODE, toInt(record[0]));
} else return BAD_VALUE;
// expect part 1 starts with "zone"
if (stripPrefix(&record[1], "zone")) {
- proto.write(MigrateTypeProto::ZONE, record[1]);
+ proto.write(PageTypeInfoProto::MigrateType::ZONE, record[1]);
} else return BAD_VALUE;
// expect part 2 starts with "type"
if (stripPrefix(&record[2], "type")) {
@@ -83,22 +85,22 @@
int pageCountsSize = pageBlockOrder + 2;
if ((int)pageCounts.size() != pageCountsSize) return BAD_VALUE;
- proto.write(MigrateTypeProto::TYPE, pageCounts[0]);
+ proto.write(PageTypeInfoProto::MigrateType::TYPE, pageCounts[0]);
for (auto i=1; i<pageCountsSize; i++) {
- proto.write(MigrateTypeProto::FREE_PAGES_COUNT, toInt(pageCounts[i]));
+ proto.write(PageTypeInfoProto::MigrateType::FREE_PAGES_COUNT, toInt(pageCounts[i]));
}
} else return BAD_VALUE;
proto.end(token);
} else if (!blockHeader.empty() && record.size() == 2) {
- long long token = proto.start(PageTypeInfo::BLOCKS);
+ long long token = proto.start(PageTypeInfoProto::BLOCKS);
if (stripPrefix(&record[0], "Node")) {
- proto.write(BlockProto::NODE, toInt(record[0]));
+ proto.write(PageTypeInfoProto::Block::NODE, toInt(record[0]));
} else return BAD_VALUE;
if (stripPrefix(&record[1], "zone")) {
record_t blockCounts = parseRecord(record[1]);
- proto.write(BlockProto::ZONE, blockCounts[0]);
+ proto.write(PageTypeInfoProto::Block::ZONE, blockCounts[0]);
for (size_t i=0; i<blockHeader.size(); i++) {
if (!table.insertField(&proto, blockHeader[i], blockCounts[i+1])) {
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
index a4eb0fd..c1c458e 100644
--- a/cmds/incident_helper/src/parsers/ProcrankParser.cpp
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -33,7 +33,7 @@
int nline = 0;
ProtoOutputStream proto;
- Table table(ProcessProto::_FIELD_NAMES, ProcessProto::_FIELD_IDS, ProcessProto::_FIELD_COUNT);
+ Table table(ProcrankProto::Process::_FIELD_NAMES, ProcrankProto::Process::_FIELD_IDS, ProcrankProto::Process::_FIELD_COUNT);
string zram, ram, total;
// parse line by line
@@ -66,7 +66,7 @@
continue;
}
- long long token = proto.start(Procrank::PROCESSES);
+ long long token = proto.start(ProcrankProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
@@ -77,23 +77,23 @@
}
// add summary
- long long token = proto.start(Procrank::SUMMARY);
+ long long token = proto.start(ProcrankProto::SUMMARY);
if (!total.empty()) {
record = parseRecord(total);
- long long token = proto.start(SummaryProto::TOTAL);
+ long long token = proto.start(ProcrankProto::Summary::TOTAL);
for (int i=(int)record.size(); i>0; i--) {
table.insertField(&proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
}
proto.end(token);
}
if (!zram.empty()) {
- long long token = proto.start(SummaryProto::ZRAM);
- proto.write(ZramProto::RAW_TEXT, zram);
+ long long token = proto.start(ProcrankProto::Summary::ZRAM);
+ proto.write(ProcrankProto::Summary::Zram::RAW_TEXT, zram);
proto.end(token);
}
if (!ram.empty()) {
- long long token = proto.start(SummaryProto::RAM);
- proto.write(RamProto::RAW_TEXT, ram);
+ long long token = proto.start(ProcrankProto::Summary::RAM);
+ proto.write(ProcrankProto::Summary::Ram::RAW_TEXT, ram);
proto.end(token);
}
proto.end(token);
diff --git a/cmds/incident_helper/src/parsers/PsParser.cpp b/cmds/incident_helper/src/parsers/PsParser.cpp
index e9014ca..420775f 100644
--- a/cmds/incident_helper/src/parsers/PsParser.cpp
+++ b/cmds/incident_helper/src/parsers/PsParser.cpp
@@ -33,12 +33,12 @@
int diff = 0;
ProtoOutputStream proto;
- Table table(PsDumpProto::Process::_FIELD_NAMES, PsDumpProto::Process::_FIELD_IDS, PsDumpProto::Process::_FIELD_COUNT);
+ Table table(PsProto::Process::_FIELD_NAMES, PsProto::Process::_FIELD_IDS, PsProto::Process::_FIELD_COUNT);
const char* pcyNames[] = { "fg", "bg", "ta" };
- const int pcyValues[] = {PsDumpProto::Process::POLICY_FG, PsDumpProto::Process::POLICY_BG, PsDumpProto::Process::POLICY_TA};
+ const int pcyValues[] = {PsProto::Process::POLICY_FG, PsProto::Process::POLICY_BG, PsProto::Process::POLICY_TA};
table.addEnumTypeMap("pcy", pcyNames, pcyValues, 3);
const char* sNames[] = { "D", "R", "S", "T", "t", "X", "Z" };
- const int sValues[] = {PsDumpProto::Process::STATE_D, PsDumpProto::Process::STATE_R, PsDumpProto::Process::STATE_S, PsDumpProto::Process::STATE_T, PsDumpProto::Process::STATE_TRACING, PsDumpProto::Process::STATE_X, PsDumpProto::Process::STATE_Z};
+ const int sValues[] = {PsProto::Process::STATE_D, PsProto::Process::STATE_R, PsProto::Process::STATE_S, PsProto::Process::STATE_T, PsProto::Process::STATE_TRACING, PsProto::Process::STATE_X, PsProto::Process::STATE_Z};
table.addEnumTypeMap("s", sNames, sValues, 7);
// Parse line by line
@@ -71,7 +71,7 @@
continue;
}
- long long token = proto.start(PsDumpProto::PROCESSES);
+ long long token = proto.start(PsProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
diff --git a/cmds/incident_helper/tests/CpuFreqParser_test.cpp b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
index 82deee4..0839a7e 100644
--- a/cmds/incident_helper/tests/CpuFreqParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
@@ -52,14 +52,14 @@
TEST_F(CpuFreqParserTest, Success) {
const string testFile = kTestDataPath + "cpufreq.txt";
CpuFreqParser parser;
- CpuFreq expected;
+ CpuFreqProto expected;
long jiffyHz = sysconf(_SC_CLK_TCK);
expected.set_jiffy_hz(jiffyHz);
- CpuFreqStats::TimeInState* state;
+ CpuFreqProto::Stats::TimeInState* state;
- CpuFreqStats* cpu0 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu0 = expected.add_cpu_freqs();
cpu0->set_cpu_name("cpu0");
state = cpu0->add_times();
state->set_state_khz(307200);
@@ -71,7 +71,7 @@
state->set_state_khz(768000);
state->set_time_jiffy(22652);
- CpuFreqStats* cpu1 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu1 = expected.add_cpu_freqs();
cpu1->set_cpu_name("cpu1");
state = cpu1->add_times();
state->set_state_khz(307200);
@@ -83,7 +83,7 @@
state->set_state_khz(768000);
state->set_time_jiffy(22652);
- CpuFreqStats* cpu2 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu2 = expected.add_cpu_freqs();
cpu2->set_cpu_name("cpu2");
state = cpu2->add_times();
state->set_state_khz(307200);
@@ -98,7 +98,7 @@
state->set_state_khz(825600);
state->set_time_jiffy(13173);
- CpuFreqStats* cpu3 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu3 = expected.add_cpu_freqs();
cpu3->set_cpu_name("cpu3");
state = cpu3->add_times();
state->set_state_khz(307200);
diff --git a/cmds/incident_helper/tests/CpuInfoParser_test.cpp b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
index 8dce53e..2e50d63 100644
--- a/cmds/incident_helper/tests/CpuInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
@@ -52,28 +52,28 @@
TEST_F(CpuInfoParserTest, Success) {
const string testFile = kTestDataPath + "cpuinfo.txt";
CpuInfoParser parser;
- CpuInfo expected;
+ CpuInfoProto expected;
- CpuInfo::TaskStats* taskStats = expected.mutable_task_stats();
+ CpuInfoProto::TaskStats* taskStats = expected.mutable_task_stats();
taskStats->set_total(2038);
taskStats->set_running(1);
taskStats->set_sleeping(2033);
taskStats->set_stopped(0);
taskStats->set_zombie(0);
- CpuInfo::MemStats* mem = expected.mutable_mem();
+ CpuInfoProto::MemStats* mem = expected.mutable_mem();
mem->set_total(3842668);
mem->set_used(3761936);
mem->set_free(80732);
mem->set_buffers(220188);
- CpuInfo::MemStats* swap = expected.mutable_swap();
+ CpuInfoProto::MemStats* swap = expected.mutable_swap();
swap->set_total(524284);
swap->set_used(25892);
swap->set_free(498392);
swap->set_cached(1316952);
- CpuInfo::CpuUsage* usage = expected.mutable_cpu_usage();
+ CpuInfoProto::CpuUsage* usage = expected.mutable_cpu_usage();
usage->set_cpu(400);
usage->set_user(17);
usage->set_nice(0);
@@ -85,59 +85,59 @@
usage->set_host(0);
// This is a special line which is able to be parsed by the CpuInfoParser
- CpuInfo::Task* task1 = expected.add_tasks();
+ CpuInfoProto::Task* task1 = expected.add_tasks();
task1->set_pid(29438);
task1->set_tid(29438);
task1->set_user("rootabcdefghij");
task1->set_pr("20");
task1->set_ni(0);
task1->set_cpu(57.9);
- task1->set_s(CpuInfo::Task::STATUS_R);
+ task1->set_s(CpuInfoProto::Task::STATUS_R);
task1->set_virt("14M");
task1->set_res("3.8M");
- task1->set_pcy(CpuInfo::Task::POLICY_UNKNOWN);
+ task1->set_pcy(CpuInfoProto::Task::POLICY_UNKNOWN);
task1->set_cmd("top test");
task1->set_name("top");
- CpuInfo::Task* task2 = expected.add_tasks();
+ CpuInfoProto::Task* task2 = expected.add_tasks();
task2->set_pid(916);
task2->set_tid(916);
task2->set_user("system");
task2->set_pr("18");
task2->set_ni(-2);
task2->set_cpu(1.4);
- task2->set_s(CpuInfo::Task::STATUS_S);
+ task2->set_s(CpuInfoProto::Task::STATUS_S);
task2->set_virt("4.6G");
task2->set_res("404M");
- task2->set_pcy(CpuInfo::Task::POLICY_fg);
+ task2->set_pcy(CpuInfoProto::Task::POLICY_fg);
task2->set_cmd("system_server");
task2->set_name("system_server");
- CpuInfo::Task* task3 = expected.add_tasks();
+ CpuInfoProto::Task* task3 = expected.add_tasks();
task3->set_pid(28);
task3->set_tid(28);
task3->set_user("root");
task3->set_pr("-2");
task3->set_ni(0);
task3->set_cpu(1.4);
- task3->set_s(CpuInfo::Task::STATUS_S);
+ task3->set_s(CpuInfoProto::Task::STATUS_S);
task3->set_virt("0");
task3->set_res("0");
- task3->set_pcy(CpuInfo::Task::POLICY_bg);
+ task3->set_pcy(CpuInfoProto::Task::POLICY_bg);
task3->set_cmd("rcuc/3");
task3->set_name("[rcuc/3]");
- CpuInfo::Task* task4 = expected.add_tasks();
+ CpuInfoProto::Task* task4 = expected.add_tasks();
task4->set_pid(27);
task4->set_tid(27);
task4->set_user("root");
task4->set_pr("RT");
task4->set_ni(0);
task4->set_cpu(1.4);
- task4->set_s(CpuInfo::Task::STATUS_S);
+ task4->set_s(CpuInfoProto::Task::STATUS_S);
task4->set_virt("0");
task4->set_res("0");
- task4->set_pcy(CpuInfo::Task::POLICY_ta);
+ task4->set_pcy(CpuInfoProto::Task::POLICY_ta);
task4->set_cmd("migration/3");
task4->set_name("[migration/3]");
diff --git a/cmds/incident_helper/tests/KernelWakesParser_test.cpp b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
index a98c62b..f92d813 100644
--- a/cmds/incident_helper/tests/KernelWakesParser_test.cpp
+++ b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
@@ -52,14 +52,14 @@
TEST_F(KernelWakesParserTest, Short) {
const string testFile = kTestDataPath + "kernel_wakeups_short.txt";
KernelWakesParser parser;
- KernelWakeSources expected;
+ KernelWakeSourcesProto expected;
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record1 = expected.add_wakeup_sources();
record1->set_name("ab");
record1->set_active_count(8);
record1->set_last_change(123456123456LL);
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record2 = expected.add_wakeup_sources();
record2->set_name("df");
record2->set_active_count(143);
record2->set_last_change(0LL);
@@ -76,9 +76,9 @@
TEST_F(KernelWakesParserTest, Normal) {
const string testFile = kTestDataPath + "kernel_wakeups.txt";
KernelWakesParser parser;
- KernelWakeSources expected;
+ KernelWakeSourcesProto expected;
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record1 = expected.add_wakeup_sources();
record1->set_name("ipc000000ab_ATFWD-daemon");
record1->set_active_count(8);
record1->set_event_count(8);
@@ -90,7 +90,7 @@
record1->set_last_change(131348LL);
record1->set_prevent_suspend_time(0LL);
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record2 = expected.add_wakeup_sources();
record2->set_name("ipc000000aa_ATFWD-daemon");
record2->set_active_count(143);
record2->set_event_count(143);
diff --git a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
index a9e6e816..9bad7be 100644
--- a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
@@ -52,12 +52,12 @@
TEST_F(PageTypeInfoParserTest, Success) {
const string testFile = kTestDataPath + "pagetypeinfo.txt";
PageTypeInfoParser parser;
- PageTypeInfo expected;
+ PageTypeInfoProto expected;
expected.set_page_block_order(10);
expected.set_pages_per_block(1024);
- MigrateTypeProto* mt1 = expected.add_migrate_types();
+ PageTypeInfoProto::MigrateType* mt1 = expected.add_migrate_types();
mt1->set_node(0);
mt1->set_zone("DMA");
mt1->set_type("Unmovable");
@@ -66,7 +66,7 @@
mt1->add_free_pages_count(arr1[i]);
}
- MigrateTypeProto* mt2 = expected.add_migrate_types();
+ PageTypeInfoProto::MigrateType* mt2 = expected.add_migrate_types();
mt2->set_node(0);
mt2->set_zone("Normal");
mt2->set_type("Reclaimable");
@@ -75,7 +75,7 @@
mt2->add_free_pages_count(arr2[i]);
}
- BlockProto* block1 = expected.add_blocks();
+ PageTypeInfoProto::Block* block1 = expected.add_blocks();
block1->set_node(0);
block1->set_zone("DMA");
block1->set_unmovable(74);
@@ -86,7 +86,7 @@
block1->set_isolate(0);
- BlockProto* block2 = expected.add_blocks();
+ PageTypeInfoProto::Block* block2 = expected.add_blocks();
block2->set_node(0);
block2->set_zone("Normal");
block2->set_unmovable(70);
diff --git a/cmds/incident_helper/tests/ProcrankParser_test.cpp b/cmds/incident_helper/tests/ProcrankParser_test.cpp
index 76b25d7..0b567ae 100644
--- a/cmds/incident_helper/tests/ProcrankParser_test.cpp
+++ b/cmds/incident_helper/tests/ProcrankParser_test.cpp
@@ -52,9 +52,9 @@
TEST_F(ProcrankParserTest, HasSwapInfo) {
const string testFile = kTestDataPath + "procrank.txt";
ProcrankParser parser;
- Procrank expected;
+ ProcrankProto expected;
- ProcessProto* process1 = expected.add_processes();
+ ProcrankProto::Process* process1 = expected.add_processes();
process1->set_pid(1119);
process1->set_vss(2607640);
process1->set_rss(339564);
@@ -66,7 +66,7 @@
process1->set_zswap(10);
process1->set_cmdline("system_server");
- ProcessProto* process2 = expected.add_processes();
+ ProcrankProto::Process* process2 = expected.add_processes();
process2->set_pid(649);
process2->set_vss(11016);
process2->set_rss(1448);
@@ -78,7 +78,7 @@
process2->set_zswap(75);
process2->set_cmdline("/vendor/bin/qseecomd");
- ProcessProto* total = expected.mutable_summary()->mutable_total();
+ ProcrankProto::Process* total = expected.mutable_summary()->mutable_total();
total->set_pss(1201993);
total->set_uss(935300);
total->set_swap(88164);
@@ -104,9 +104,9 @@
TEST_F(ProcrankParserTest, NoSwapInfo) {
const string testFile = kTestDataPath + "procrank_short.txt";
ProcrankParser parser;
- Procrank expected;
+ ProcrankProto expected;
- ProcessProto* process1 = expected.add_processes();
+ ProcrankProto::Process* process1 = expected.add_processes();
process1->set_pid(1119);
process1->set_vss(2607640);
process1->set_rss(339564);
@@ -114,7 +114,7 @@
process1->set_uss(114216);
process1->set_cmdline("system_server");
- ProcessProto* process2 = expected.add_processes();
+ ProcrankProto::Process* process2 = expected.add_processes();
process2->set_pid(649);
process2->set_vss(11016);
process2->set_rss(1448);
@@ -122,7 +122,7 @@
process2->set_uss(48);
process2->set_cmdline("/vendor/bin/qseecomd");
- ProcessProto* total = expected.mutable_summary()->mutable_total();
+ ProcrankProto::Process* total = expected.mutable_summary()->mutable_total();
total->set_pss(1201993);
total->set_uss(935300);
total->set_cmdline("TOTAL");
diff --git a/cmds/incident_helper/tests/PsParser_test.cpp b/cmds/incident_helper/tests/PsParser_test.cpp
index 1f03a7f..114d634 100644
--- a/cmds/incident_helper/tests/PsParser_test.cpp
+++ b/cmds/incident_helper/tests/PsParser_test.cpp
@@ -52,10 +52,10 @@
TEST_F(PsParserTest, Normal) {
const string testFile = kTestDataPath + "ps.txt";
PsParser parser;
- PsDumpProto expected;
- PsDumpProto got;
+ PsProto expected;
+ PsProto got;
- PsDumpProto::Process* record1 = expected.add_processes();
+ PsProto::Process* record1 = expected.add_processes();
record1->set_label("u:r:init:s0");
record1->set_user("root");
record1->set_pid(1);
@@ -65,16 +65,16 @@
record1->set_rss(2636);
record1->set_wchan("SyS_epoll_wait");
record1->set_addr("0");
- record1->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record1->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record1->set_pri(19);
record1->set_ni(0);
record1->set_rtprio("-");
- record1->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record1->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record1->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record1->set_pcy(PsProto::Process::POLICY_FG);
record1->set_time("00:00:01");
record1->set_cmd("init");
- PsDumpProto::Process* record2 = expected.add_processes();
+ PsProto::Process* record2 = expected.add_processes();
record2->set_label("u:r:kernel:s0");
record2->set_user("root");
record2->set_pid(2);
@@ -84,16 +84,16 @@
record2->set_rss(0);
record2->set_wchan("kthreadd");
record2->set_addr("0");
- record2->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record2->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record2->set_pri(19);
record2->set_ni(0);
record2->set_rtprio("-");
- record2->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record2->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record2->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record2->set_pcy(PsProto::Process::POLICY_FG);
record2->set_time("00:00:00");
record2->set_cmd("kthreadd");
- PsDumpProto::Process* record3 = expected.add_processes();
+ PsProto::Process* record3 = expected.add_processes();
record3->set_label("u:r:surfaceflinger:s0");
record3->set_user("system");
record3->set_pid(499);
@@ -103,16 +103,16 @@
record3->set_rss(22024);
record3->set_wchan("futex_wait_queue_me");
record3->set_addr("0");
- record3->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record3->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record3->set_pri(42);
record3->set_ni(-9);
record3->set_rtprio("2");
- record3->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_FIFO);
- record3->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record3->set_sch(PsProto_Process_SchedulingPolicy_SCH_FIFO);
+ record3->set_pcy(PsProto::Process::POLICY_FG);
record3->set_time("00:00:00");
record3->set_cmd("EventThread");
- PsDumpProto::Process* record4 = expected.add_processes();
+ PsProto::Process* record4 = expected.add_processes();
record4->set_label("u:r:hal_gnss_default:s0");
record4->set_user("gps");
record4->set_pid(670);
@@ -122,16 +122,16 @@
record4->set_rss(7272);
record4->set_wchan("poll_schedule_timeout");
record4->set_addr("0");
- record4->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record4->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record4->set_pri(19);
record4->set_ni(0);
record4->set_rtprio("-");
- record4->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record4->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record4->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record4->set_pcy(PsProto::Process::POLICY_FG);
record4->set_time("00:00:00");
record4->set_cmd("Loc_hal_worker");
- PsDumpProto::Process* record5 = expected.add_processes();
+ PsProto::Process* record5 = expected.add_processes();
record5->set_label("u:r:platform_app:s0:c512,c768");
record5->set_user("u0_a48");
record5->set_pid(1660);
@@ -141,16 +141,16 @@
record5->set_rss(138328);
record5->set_wchan("binder_thread_read");
record5->set_addr("0");
- record5->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record5->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record5->set_pri(35);
record5->set_ni(-16);
record5->set_rtprio("-");
- record5->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record5->set_pcy(PsDumpProto::Process::POLICY_TA);
+ record5->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record5->set_pcy(PsProto::Process::POLICY_TA);
record5->set_time("00:00:00");
record5->set_cmd("HwBinder:1660_1");
- PsDumpProto::Process* record6 = expected.add_processes();
+ PsProto::Process* record6 = expected.add_processes();
record6->set_label("u:r:perfd:s0");
record6->set_user("root");
record6->set_pid(1939);
@@ -160,16 +160,16 @@
record6->set_rss(2088);
record6->set_wchan("__skb_recv_datagram");
record6->set_addr("7b9782fd14");
- record6->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record6->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record6->set_pri(19);
record6->set_ni(0);
record6->set_rtprio("-");
- record6->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record6->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record6->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record6->set_pcy(PsProto::Process::POLICY_UNKNOWN);
record6->set_time("00:00:00");
record6->set_cmd("perfd");
- PsDumpProto::Process* record7 = expected.add_processes();
+ PsProto::Process* record7 = expected.add_processes();
record7->set_label("u:r:perfd:s0");
record7->set_user("root");
record7->set_pid(1939);
@@ -179,16 +179,16 @@
record7->set_rss(2088);
record7->set_wchan("do_sigtimedwait");
record7->set_addr("7b9782ff6c");
- record7->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record7->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record7->set_pri(19);
record7->set_ni(0);
record7->set_rtprio("-");
- record7->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record7->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record7->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record7->set_pcy(PsProto::Process::POLICY_UNKNOWN);
record7->set_time("00:00:00");
record7->set_cmd("POSIX timer 0");
- PsDumpProto::Process* record8 = expected.add_processes();
+ PsProto::Process* record8 = expected.add_processes();
record8->set_label("u:r:shell:s0");
record8->set_user("shell");
record8->set_pid(2645);
@@ -198,12 +198,12 @@
record8->set_rss(2972);
record8->set_wchan("0");
record8->set_addr("7f67a2f8b4");
- record8->set_s(PsDumpProto_Process_ProcessStateCode_STATE_R);
+ record8->set_s(PsProto_Process_ProcessStateCode_STATE_R);
record8->set_pri(19);
record8->set_ni(0);
record8->set_rtprio("-");
- record8->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record8->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record8->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record8->set_pcy(PsProto::Process::POLICY_FG);
record8->set_time("00:00:00");
record8->set_cmd("ps");
@@ -221,8 +221,8 @@
} else {
int n = got.processes_size();
for (int i = 0; i < n; i++) {
- PsDumpProto::Process g = got.processes(i);
- PsDumpProto::Process e = expected.processes(i);
+ PsProto::Process g = got.processes(i);
+ PsProto::Process e = expected.processes(i);
if (g.label() != e.label()) {
fprintf(stderr, "prcs[%d]: Invalid label. Got %s, want %s\n", i, g.label().c_str(), e.label().c_str());
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 67b9089..740fdc0 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -116,10 +116,8 @@
LOCAL_CFLAGS += \
-Wall \
+ -Wextra \
-Werror \
- -Wno-missing-field-initializers \
- -Wno-unused-variable \
- -Wno-unused-function \
-Wno-unused-parameter
ifeq (debug,)
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 7b0b69a..6894bcf 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -23,6 +23,23 @@
namespace os {
namespace statsd {
+int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) {
+ int32_t field = 0;
+ for (int32_t i = 0; i <= depth; i++) {
+ int32_t shiftBits = 8 * (kMaxLogDepth - i);
+ field |= (pos[i] << shiftBits);
+ }
+
+ if (includeDepth) {
+ field |= (depth << 24);
+ }
+ return field;
+}
+
+int32_t encodeMatcherMask(int32_t mask[], int32_t depth) {
+ return getEncodedField(mask, depth, false) | 0xff000000;
+}
+
bool Field::matches(const Matcher& matcher) const {
if (mTag != matcher.mMatcher.getTag()) {
return false;
@@ -32,7 +49,7 @@
}
return false;
-};
+}
void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask,
std::vector<Matcher>* output) {
@@ -71,7 +88,6 @@
if (matcher.child_size() == 0) {
output->push_back(Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth)));
- Matcher matcher = Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth));
} else {
for (const auto& child : matcher.child()) {
translateFieldMatcher(tag, child, depth + 1, pos, mask, output);
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 7484108..d17dded 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -33,29 +33,14 @@
enum Type { INT, LONG, FLOAT, STRING };
+int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);
-static int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) {
- int32_t field = 0;
- for (int32_t i = 0; i <= depth; i++) {
- int32_t shiftBits = 8 * (kMaxLogDepth - i);
- field |= (pos[i] << shiftBits);
- }
-
- if (includeDepth) {
- field |= (depth << 24);
- }
- return field;
-}
-
-static int32_t encodeMatcherMask(int32_t mask[], int32_t depth) {
- return getEncodedField(mask, depth, false) | 0xff000000;
-}
+int32_t encodeMatcherMask(int32_t mask[], int32_t depth);
// Get the encoded field for a leaf with a [field] number at depth 0;
-static int32_t getSimpleField(size_t field) {
+inline int32_t getSimpleField(size_t field) {
return ((int32_t)field << 8 * 2);
}
-
/**
* Field is a wrapper class for 2 integers that represents the field of a log element in its Atom
* proto.
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 68e2176..d901bd6 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -68,7 +68,6 @@
for (const auto& value : values) {
// TODO: potential optimization here to break early because all fields are naturally
// sorted.
- int32_t filteredField;
if (value.mField.matches(matcher)) {
matchedResults.push_back(FieldValue(
Field(value.mField.getTag(), (value.mField.getField() & matcher.mMask)),
@@ -148,7 +147,6 @@
const std::vector<FieldValue>& values, std::vector<FieldValue>* output) {
for (const auto& field : matcherFields) {
for (const auto& value : values) {
- int filteredField;
if (value.mField.matches(field)) {
output->push_back(value);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index afb2c47..87dec5d 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -58,7 +58,7 @@
const int FIELD_ID_UID = 1;
const int FIELD_ID_ID = 2;
// for ConfigMetricsReport
-const int FIELD_ID_METRICS = 1;
+// const int FIELD_ID_METRICS = 1; // written in MetricsManager.cpp
const int FIELD_ID_UID_MAP = 2;
const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3;
const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index bb47653..0a4e412 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -124,8 +124,6 @@
*/
status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
- status_t err;
-
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
@@ -240,8 +238,8 @@
return cmd_write_data_to_disk(out);
}
- if (!args[0].compare(String8("log-app-hook"))) {
- return cmd_log_app_hook(out, args);
+ if (!args[0].compare(String8("log-app-breadcrumb"))) {
+ return cmd_log_app_breadcrumb(out, args);
}
if (!args[0].compare(String8("clear-puller-cache"))) {
@@ -284,8 +282,8 @@
fprintf(out, " Flushes all data on memory to disk.\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats log-app-hook [UID] LABEL STATE\n");
- fprintf(out, " Writes an AppHook event to the statslog buffer.\n");
+ fprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
+ fprintf(out, " Writes an AppBreadcrumbReported event to the statslog buffer.\n");
fprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
fprintf(out, " uid is used.\n");
@@ -551,7 +549,7 @@
return NO_ERROR;
}
-status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args) {
bool good = false;
int32_t uid;
int32_t label;
@@ -573,13 +571,13 @@
good = true;
} else {
fprintf(out,
- "Selecting a UID for writing AppHook can only be dumped for other UIDs on eng"
+ "Selecting a UID for writing Appbreadcrumb can only be dumped for other UIDs on eng"
" or userdebug builds.\n");
}
}
if (good) {
- fprintf(out, "Logging AppHook(%d, %d, %d) to statslog.\n", uid, label, state);
- android::util::stats_write(android::util::APP_HOOK, uid, label, state);
+ fprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
+ android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
} else {
print_cmd_help(out);
return UNKNOWN_ERROR;
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 3dc19fe..fd65869 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -193,9 +193,10 @@
status_t cmd_write_data_to_disk(FILE* out);
/**
- * Write an AppHook event to the StatsLog buffer, as though StatsLog.write(APP_HOOK).
+ * Write an AppBreadcrumbReported event to the StatsLog buffer, as though StatsLog.write
+ * (APP_BREADCRUMB_REPORTED).
*/
- status_t cmd_log_app_hook(FILE* out, const Vector<String8>& args);
+ status_t cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args);
/**
* Print contents of a pulled metrics source.
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4c6a36b..1224504 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -85,7 +85,7 @@
PacketWakeupOccurred packet_wakeup_occurred = 44;
DropboxErrorChanged dropbox_error_changed = 45;
AnomalyDetected anomaly_detected = 46;
- AppHook app_hook = 47;
+ AppBreadcrumbReported app_breadcrumb_reported = 47;
AppStartChanged app_start_changed = 48;
AppStartCancelChanged app_start_cancel_changed = 49;
AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50;
@@ -202,9 +202,10 @@
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message ProcessLifeCycleStateChanged {
- optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+ // TODO: should be a string tagged w/ uid annotation
+ optional int32 uid = 1;
- // TODO: What is this?
+ // The process name (usually same as the app name).
optional string name = 2;
// What lifecycle state the process changed to.
@@ -312,7 +313,7 @@
message SyncStateChanged {
repeated AttributionNode attribution_node = 1;
- // Name of the sync (as named in the app)
+ // Name of the sync (as named in the app). Can be chosen at run-time.
optional string name = 2;
enum State {
@@ -615,7 +616,7 @@
optional string wakeup_reason_name = 1;
// Duration (in microseconds) for the wake-up interrupt to be serviced.
- optional int64 duration_usec = 2;
+ optional int64 duration_micros = 2;
}
/**
@@ -692,10 +693,10 @@
// Beginning of shutdown time in ms using wall clock time since unix epoch.
// Default: 0 if no start time received.
- optional int64 start_time_ms = 3;
+ optional int64 start_time_millis = 3;
// Duration of shutdown in ms. Default: 0 if no duration received.
- optional int64 duration_ms = 4;
+ optional int64 duration_millis = 4;
}
@@ -715,13 +716,13 @@
optional string system_reason = 2;
// End of boot time in ms from unix epoch using system wall clock.
- optional int64 end_time_ms = 3;
+ optional int64 end_time_millis = 3;
// Total boot duration in ms.
- optional int64 total_duration_ms = 4;
+ optional int64 total_duration_millis = 4;
// Bootloader duration in ms.
- optional int64 bootloader_duration_ms = 5;
+ optional int64 bootloader_duration_millis = 5;
// Time since last boot in ms. Default: 0 if not available.
optional int64 time_since_last_boot = 6;
@@ -762,7 +763,7 @@
*/
message DaveyOccurred {
// Amount of time it took to render the frame. Should be >=700ms.
- optional int64 jank_duration_ms = 1;
+ optional int64 jank_duration_millis = 1;
}
/**
@@ -863,7 +864,7 @@
* Logged from:
* frameworks/base/core/java/android/util/StatsLog.java
*/
-message AppHook {
+message AppBreadcrumbReported {
// The uid of the application that sent this custom atom.
optional int32 uid = 1;
@@ -924,16 +925,16 @@
optional bool is_instant_app = 6;
// Device uptime when activity started.
- optional int64 activity_start_msec = 7;
+ optional int64 activity_start_millis = 7;
optional android.app.AppTransitionReasonEnum reason = 8;
- optional int32 transition_delay_msec = 9;
+ optional int32 transition_delay_millis = 9;
// -1 if not set.
- optional int32 starting_window_delay_msec = 10;
+ optional int32 starting_window_delay_millis = 10;
// -1 if not set.
- optional int32 bind_application_delay_msec = 11;
- optional int32 windows_drawn_delay_msec = 12;
+ optional int32 bind_application_delay_millis = 11;
+ optional int32 windows_drawn_delay_millis = 12;
// Empty if not set.
optional string launch_token = 13;
@@ -981,7 +982,7 @@
optional bool transition_process_running = 5;
// App startup time (until call to Activity#reportFullyDrawn()).
- optional int64 app_startup_time_ms = 6;
+ optional int64 app_startup_time_millis = 6;
}
/**
@@ -1303,7 +1304,7 @@
// The number of times it entered, or voted for entering the sleep state
optional uint64 count = 3;
// The length of time spent in, or spent voting for, the sleep state
- optional uint64 timeMs = 4;
+ optional uint64 time_millis = 4;
}
/**
@@ -1316,7 +1317,7 @@
message CpuTimePerFreq {
optional uint32 cluster = 1;
optional uint32 freq_index = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/**
@@ -1325,8 +1326,8 @@
*/
message CpuTimePerUid {
optional uint64 uid = 1;
- optional uint64 user_time_ms = 2;
- optional uint64 sys_time_ms = 3;
+ optional uint64 user_time_millis = 2;
+ optional uint64 sys_time_millis = 3;
}
/**
@@ -1337,7 +1338,7 @@
message CpuTimePerUidFreq {
optional uint64 uid = 1;
optional uint64 freq_idx = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/**
@@ -1345,16 +1346,16 @@
*/
message WifiActivityEnergyInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// stack reported state
// TODO: replace this with proto enum
optional int32 stack_state = 2;
// tx time in ms
- optional uint64 controller_tx_time_ms = 3;
+ optional uint64 controller_tx_time_millis = 3;
// rx time in ms
- optional uint64 controller_rx_time_ms = 4;
+ optional uint64 controller_rx_time_millis = 4;
// idle time in ms
- optional uint64 controller_idle_time_ms = 5;
+ optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 controller_energy_used = 6;
}
@@ -1364,11 +1365,11 @@
*/
message ModemActivityInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// sleep time in ms.
- optional uint64 sleep_time_ms = 2;
+ optional uint64 sleep_time_millis = 2;
// idle time in ms
- optional uint64 controller_idle_time_ms = 3;
+ optional uint64 controller_idle_time_millis = 3;
/**
* Tx power index
* index 0 = tx_power < 0dBm
@@ -1378,17 +1379,17 @@
* index 4 = tx_power > 20dBm
*/
// tx time in ms at power level 0
- optional uint64 controller_tx_time_pl0_ms = 4;
+ optional uint64 controller_tx_time_pl0_millis = 4;
// tx time in ms at power level 1
- optional uint64 controller_tx_time_pl1_ms = 5;
+ optional uint64 controller_tx_time_pl1_millis = 5;
// tx time in ms at power level 2
- optional uint64 controller_tx_time_pl2_ms = 6;
+ optional uint64 controller_tx_time_pl2_millis = 6;
// tx time in ms at power level 3
- optional uint64 controller_tx_time_pl3_ms = 7;
+ optional uint64 controller_tx_time_pl3_millis = 7;
// tx time in ms at power level 4
- optional uint64 controller_tx_time_pl4_ms = 8;
+ optional uint64 controller_tx_time_pl4_millis = 8;
// rx time in ms at power level 5
- optional uint64 controller_rx_time_ms = 9;
+ optional uint64 controller_rx_time_millis = 9;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 10;
}
@@ -1399,15 +1400,15 @@
*/
message BluetoothActivityInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// bluetooth stack state
optional int32 bluetooth_stack_state = 2;
// tx time in ms
- optional uint64 controller_tx_time_ms = 3;
+ optional uint64 controller_tx_time_millis = 3;
// rx time in ms
- optional uint64 controller_rx_time_ms = 4;
+ optional uint64 controller_rx_time_millis = 4;
// idle time in ms
- optional uint64 controller_idle_time_ms = 5;
+ optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 6;
}
@@ -1445,7 +1446,7 @@
* Elapsed real time from SystemClock.
*/
message SystemElapsedRealtime {
- optional uint64 time_ms = 1;
+ optional uint64 time_millis = 1;
}
/*
@@ -1456,7 +1457,7 @@
// This clock stops when the system enters deep sleep (CPU off, display dark, device waiting
// for external input).
// It is not affected by clock scaling, idle, or other power saving mechanisms.
- optional uint64 uptime_ms = 1;
+ optional uint64 uptime_millis = 1;
}
/*
@@ -1470,8 +1471,9 @@
*/
message CpuActiveTime {
optional uint64 uid = 1;
- optional uint64 idx = 2;
- optional uint64 time_ms = 3;
+ optional uint32 cluster_number =2;
+ optional uint64 idx = 3;
+ optional uint64 time_millis = 4;
}
/**
@@ -1486,7 +1488,7 @@
message CpuClusterTime {
optional uint64 uid = 1;
optional uint64 idx = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/*
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index e2e9426..66cb1d0 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -45,18 +45,9 @@
const int FIELD_ID_ATOM_STATS = 7;
const int FIELD_ID_UIDMAP_STATS = 8;
const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
-const int FIELD_ID_PULLED_ATOM_STATS = 10;
+// const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp
const int FIELD_ID_LOGGER_ERROR_STATS = 11;
-const int FIELD_ID_MATCHER_STATS_NAME = 1;
-const int FIELD_ID_MATCHER_STATS_COUNT = 2;
-
-const int FIELD_ID_CONDITION_STATS_NAME = 1;
-const int FIELD_ID_CONDITION_STATS_COUNT = 2;
-
-const int FIELD_ID_METRIC_STATS_NAME = 1;
-const int FIELD_ID_METRIC_STATS_COUNT = 2;
-
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 7489d9b..f07fc66 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -178,10 +178,6 @@
void LogEvent::init(android_log_context context) {
android_log_list_element elem;
int i = 0;
-
- int seenListStart = 0;
-
- int32_t field = 0;
int depth = -1;
int pos[] = {1, 1, 1};
do {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 178db1a..af2e362 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -63,7 +63,8 @@
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket()) {
- mBucketSizeNs = TimeUnitToBucketSizeInMillis(metric.bucket()) * 1000000;
+ mBucketSizeNs =
+ TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
} else {
mBucketSizeNs = LLONG_MAX;
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index af22578c..3b7936d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -72,7 +72,8 @@
// them in the base class, because the proto generated CountMetric, and DurationMetric are
// not related. Maybe we should add a template in the future??
if (metric.has_bucket()) {
- mBucketSizeNs = TimeUnitToBucketSizeInMillis(metric.bucket()) * 1000000;
+ mBucketSizeNs =
+ TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
} else {
mBucketSizeNs = LLONG_MAX;
}
@@ -150,10 +151,9 @@
std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
- ConditionState conditionState = mWizard->getMetConditionDimension(
- mConditionTrackerIndex, mDimensionsInCondition, &conditionDimensionsKeySet);
+ mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
+ &conditionDimensionsKeySet);
- bool condition = (conditionState == ConditionState::kTrue);
for (auto& pair : mCurrentSlicedDurationTrackerMap) {
conditionDimensionsKeySet.erase(pair.first.getDimensionKeyInCondition());
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index af3b4c5..0daa506 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -69,7 +69,7 @@
mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
- bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
+ bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
} else {
bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
}
@@ -334,7 +334,6 @@
}
void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
- status_t err = NO_ERROR;
for (const auto& slice : *mCurrentSlicedBucket) {
if (slice.second.empty()) {
continue;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index e8f8299..574c59f 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -137,6 +137,11 @@
return mBucketSizeNs;
}
+ // Only needed for unit-testing to override guardrail.
+ void setBucketSize(int64_t bucketSize) {
+ mBucketSizeNs = bucketSize;
+ }
+
inline const int64_t& getMetricId() {
return mMetricId;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index ae48c52..66e1aeb 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -188,7 +188,7 @@
return;
}
- if (event.GetTagId() == android::util::APP_HOOK) { // Check that app hook fields are valid.
+ if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) { // Check that app hook fields are valid.
// TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
status_t err = NO_ERROR;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index cbca884..35fcdc4 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -72,7 +72,7 @@
// TODO: valuemetric for pushed events may need unlimited bucket length
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
- bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
+ bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
} else {
bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index c29876b..95df5ae6 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -177,7 +177,6 @@
false; // has either a kStarted or kPaused event across bucket boundaries
// meaning we need to carry them over to the new bucket.
for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
- int64_t finalDuration = it->second.lastDuration;
if (it->second.state == DurationState::kStopped) {
// No need to keep buckets for events that were stopped before.
mInfos.erase(it);
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index e735770..30eef4f 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -17,6 +17,7 @@
#include "stats_log_util.h"
#include <logd/LogEvent.h>
+#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <set>
#include <stack>
@@ -41,15 +42,12 @@
const int DIMENSIONS_VALUE_VALUE_STR = 2;
const int DIMENSIONS_VALUE_VALUE_INT = 3;
const int DIMENSIONS_VALUE_VALUE_LONG = 4;
-const int DIMENSIONS_VALUE_VALUE_BOOL = 5;
+// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
-// for MessageValue Proto
-const int FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO = 1;
-
// for PulledAtomStats proto
const int FIELD_ID_PULLED_ATOM_STATS = 10;
const int FIELD_ID_PULL_ATOM_ID = 1;
@@ -131,11 +129,6 @@
protoOutput->end(topToken);
}
-// for Field Proto
-const int FIELD_FIELD = 1;
-const int FIELD_POSITION_INDEX = 2;
-const int FIELD_CHILD = 3;
-
// Supported Atoms format
// XYZ_Atom {
// repeated SubMsg field_1 = 1;
@@ -224,6 +217,14 @@
protoOutput->end(atomToken);
}
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
+ int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
+ if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) {
+ bucketSizeMillis = 5 * 60 * 1000LL;
+ }
+ return bucketSizeMillis;
+}
+
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
switch (unit) {
case ONE_MINUTE:
@@ -291,4 +292,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index 32fe0b8..6a5123d 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -32,6 +32,10 @@
void writeDimensionToProto(const HashableDimensionKey& dimension,
util::ProtoOutputStream* protoOutput);
+// Convert the TimeUnit enum to the bucket size in millis with a guardrail on
+// bucket size.
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit);
+
// Convert the TimeUnit enum to the bucket size in millis.
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit);
@@ -71,4 +75,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 93cd587..0228004 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -47,7 +47,7 @@
*countMetric->mutable_dimensions_in_what() =
CreateAttributionUidAndTagDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- countMetric->set_bucket(ONE_MINUTE);
+ countMetric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -206,4 +206,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
index 293f579..4dffd13 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
@@ -61,7 +61,7 @@
CreateDimensions(android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
*metric->mutable_dimensions_in_condition() = CreateAttributionUidDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -252,7 +252,7 @@
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_count_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("AppCrashMetric"));
metric->set_what(appCrashMatcher.id());
metric->set_condition(combinationPredicate->id());
@@ -441,7 +441,7 @@
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_duration_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("BatterySaverModeDurationMetric"));
metric->set_what(inBatterySaverModePredicate.id());
metric->set_condition(combinationPredicate->id());
@@ -595,7 +595,7 @@
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_duration_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("AppInBackgroundMetric"));
metric->set_what(isInBackgroundPredicate.id());
metric->set_condition(combinationPredicate->id());
@@ -730,4 +730,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
index 674d810..3843e0a 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
@@ -53,7 +53,7 @@
fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
*gaugeMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
- gaugeMetric->set_bucket(ONE_MINUTE);
+ gaugeMetric->set_bucket(FIVE_MINUTES);
auto links = gaugeMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
@@ -161,21 +161,21 @@
EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::HOT);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name2");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_msec(), 102L);
+ EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 102L);
EXPECT_EQ(data.bucket_info(1).atom_size(), 1);
EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().type(), AppStartChanged::WARM);
EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_name(), "activity_name4");
- EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_msec(), 104L);
+ EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_millis(), 104L);
EXPECT_EQ(data.bucket_info(2).atom_size(), 1);
EXPECT_EQ(data.bucket_info(2).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(2).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().type(), AppStartChanged::COLD);
EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_name(), "activity_name5");
- EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_msec(), 105L);
+ EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_millis(), 105L);
data = gaugeMetrics.data(1);
@@ -189,7 +189,7 @@
EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::COLD);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name7");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_msec(), 201L);
+ EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 201L);
}
#else
@@ -198,4 +198,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index d005181..1b51780 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -71,7 +71,7 @@
// The metric is dimensioning by uid only.
*countMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
- countMetric->set_bucket(ONE_MINUTE);
+ countMetric->set_bucket(FIVE_MINUTES);
// Links between crash atom and condition of app is in syncing.
auto links = countMetric->add_links();
@@ -337,4 +337,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 024fa3e..efdab98 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -56,7 +56,7 @@
*durationMetric->mutable_dimensions_in_what() =
CreateAttributionUidDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- durationMetric->set_bucket(ONE_MINUTE);
+ durationMetric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -327,4 +327,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index d9dbf1d..20ddbe9 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -56,6 +56,7 @@
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
// 2 events in bucket 1.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -118,6 +119,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
countProducer.onConditionChanged(true, bucketStartTimeNs);
countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
@@ -179,6 +181,7 @@
CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
@@ -217,6 +220,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -274,6 +279,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
// Bucket is flushed yet.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -329,6 +335,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
int tagId = 1;
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 57e2794..7969596 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -59,6 +59,7 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
@@ -100,6 +101,8 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
+
EXPECT_FALSE(durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -149,6 +152,7 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
LogEvent start_event(tagId, startTimeNs);
start_event.init();
@@ -203,6 +207,7 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
LogEvent start_event(tagId, startTimeNs);
start_event.init();
@@ -256,6 +261,8 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -293,6 +300,7 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
LogEvent start_event(tagId, startTimeNs);
start_event.init();
@@ -340,6 +348,7 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
LogEvent start_event(tagId, startTimeNs);
start_event.init();
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 8b4273b..0eb8ce2 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -67,6 +67,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -144,6 +145,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /* -1 means no pulling */, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -225,6 +227,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -292,6 +295,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId,
bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -350,6 +354,7 @@
gaugeFieldMatcher->add_child()->set_field(2);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
Alert alert;
alert.set_id(101);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 6e66c6e..ce4fa32 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -66,6 +66,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -79,6 +80,8 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
// startUpdated:true tainted:0 sum:0 start:11
EXPECT_EQ(true, curInterval.startUpdated);
EXPECT_EQ(0, curInterval.tainted);
@@ -162,7 +165,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
pullerManager);
-
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
@@ -215,6 +218,7 @@
make_shared<StrictMock<MockStatsPullerManager>>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -269,6 +273,7 @@
}));
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -311,6 +316,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -357,6 +363,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /*not pulled*/, bucketStartTimeNs);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index f7c5c57..fb27f74 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -7,33 +7,3 @@
name: "IDropBoxManagerService.aidl",
srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
}
-
-// only used by key_store_service
-cc_library_shared {
- name: "libkeystore_aidl",
- srcs: ["android/security/IKeystoreService.aidl",
- "android/security/IConfirmationPromptCallback.aidl"],
- aidl: {
- export_aidl_headers: true,
- include_dirs: [
- "frameworks/base/core/java/",
- "system/security/keystore/",
- ],
- },
- shared_libs: [
- "libbinder",
- "libcutils",
- "libhardware",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libkeystore_parcelables",
- "libselinux",
- "libutils",
- ],
- export_shared_lib_headers: [
- "libbinder",
- "libkeystore_parcelables",
- ],
-}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bcd88fe..3283759 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7751,7 +7751,6 @@
* @param disable {@code true} to disable preview screenshots; {@code false} otherwise.
* @hide
*/
- @SystemApi
public void setDisablePreviewScreenshots(boolean disable) {
try {
ActivityManager.getService().setDisablePreviewScreenshots(mToken, disable);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index fee5827..d5430f0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1106,6 +1106,11 @@
}
/** @hide */
+ public void setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter) {
+ mRemoteAnimationAdapter = remoteAnimationAdapter;
+ }
+
+ /** @hide */
public static ActivityOptions fromBundle(Bundle bOptions) {
return bOptions != null ? new ActivityOptions(bOptions) : null;
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 02be002..60dccbc 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -68,6 +68,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -696,4 +697,11 @@
* Registers remote animations for a specific activity.
*/
void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
+
+ /**
+ * Registers a remote animation to be run for all activity starts from a certain package during
+ * a short predefined amount of time.
+ */
+ void registerRemoteAnimationForNextActivityStart(in String packageName,
+ in RemoteAnimationAdapter adapter);
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 0f1c249..1312a2e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1303,6 +1303,17 @@
}
/**
+ * @hide
+ */
+ public void setWebDomain(@Nullable String domain) {
+ if (domain == null) return;
+
+ final Uri uri = Uri.parse(domain);
+ mWebScheme = uri.getScheme();
+ mWebDomain = uri.getHost();
+ }
+
+ /**
* Returns the scheme of the HTML document represented by this view.
*
* <p>Typically used when the view associated with the view is a container for an HTML
@@ -1889,14 +1900,7 @@
@Override
public void setWebDomain(@Nullable String domain) {
- if (domain == null) {
- mNode.mWebScheme = null;
- mNode.mWebDomain = null;
- return;
- }
- Uri uri = Uri.parse(domain);
- mNode.mWebScheme = uri.getScheme();
- mNode.mWebDomain = uri.getHost();
+ mNode.setWebDomain(domain);
}
@Override
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index 9a50a00..7f8c50c 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -91,4 +91,9 @@
pw.println(prefix + "target state:" + getTargetState());
pw.println(prefix + "description: " + mDescription);
}
+
+ @Override
+ public void recycle() {
+ setDescription(null);
+ }
}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index 48a79f7..0edcf18 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -65,6 +65,7 @@
@Override
public void recycle() {
+ super.recycle();
mFinished = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index 70a4755..91e73cd 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -102,6 +102,7 @@
@Override
public void recycle() {
+ super.recycle();
mFinished = false;
mUserLeaving = false;
mConfigChanges = 0;
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index ed90f2c..af2fb71 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -101,6 +101,7 @@
@Override
public void recycle() {
+ super.recycle();
mProcState = ActivityManager.PROCESS_STATE_UNKNOWN;
mUpdateProcState = false;
mIsForward = false;
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index b814d1a..f955a90 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -72,6 +72,7 @@
@Override
public void recycle() {
+ super.recycle();
mShowWindow = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index bc7823b..1dc7549 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2307,6 +2307,9 @@
} else if (profile == BluetoothProfile.HID_DEVICE) {
BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HEARING_AID) {
+ BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);
+ return true;
} else {
return false;
}
@@ -2389,6 +2392,9 @@
BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy;
hidDevice.close();
break;
+ case BluetoothProfile.HEARING_AID:
+ BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
+ hearingAid.close();
}
}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
new file mode 100644
index 0000000..647e0d0
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -0,0 +1,693 @@
+/*
+ * Copyright 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.bluetooth;
+
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class provides the public APIs to control the Bluetooth Hearing Aid
+ * profile.
+ *
+ * <p>BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothHearingAid proxy object.
+ *
+ * <p> Each method is protected with its appropriate permission.
+ * @hide
+ */
+public final class BluetoothHearingAid implements BluetoothProfile {
+ private static final String TAG = "BluetoothHearingAid";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Hearing Aid
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the Hearing Aid
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PLAYING_STATE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the selection of a connected device as active.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ACTIVE_DEVICE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
+
+ /**
+ * Hearing Aid device is streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_PLAYING = 10;
+
+ /**
+ * Hearing Aid device is NOT streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_NOT_PLAYING = 11;
+
+ /** This device represents Left Hearing Aid. */
+ public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT;
+
+ /** This device represents Right Hearing Aid. */
+ public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT;
+
+ /** This device is Monaural. */
+ public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL;
+
+ /** This device is Binaural (should receive only left or right audio). */
+ public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL;
+
+ /** Can't read ClientID for this device */
+ public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("mServiceLock")
+ private IBluetoothHearingAid mService;
+ private BluetoothAdapter mAdapter;
+
+ private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG, "Unbinding service...");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ } else {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ if (VDBG) Log.d(TAG, "Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothHearingAid proxy object for interacting with the local
+ * Bluetooth Hearing Aid service.
+ */
+ /*package*/ BluetoothHearingAid(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ doBind();
+ }
+
+ void doBind() {
+ Intent intent = new Intent(IBluetoothHearingAid.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Hearing Aid Service with " + intent);
+ return;
+ }
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ try {
+ mServiceLock.writeLock().lock();
+ if (mService != null) {
+ mService = null;
+ mContext.unbindService(mConnection);
+ }
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void finalize() {
+ // The empty finalize needs to be kept or the
+ // cts signature tests would fail.
+ }
+
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ return mService.connect(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ return mService.disconnect(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getConnectedDevices();
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getDevicesMatchingConnectionStates(states);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getConnectionState(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
+ * {@link #PRIORITY_OFF},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ * @hide
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF
+ && priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ return mService.setPriority(device, priority);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getPriority(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ *
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ case STATE_PLAYING:
+ return "playing";
+ case STATE_NOT_PLAYING:
+ return "not playing";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ /**
+ * Get the volume of the device.
+ *
+ * <p> The volume is between -128 dB (mute) to 0 dB.
+ *
+ * @return volume of the hearing aid device.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getVolume() {
+ if (VDBG) {
+ log("getVolume()");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getVolume();
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return 0;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return 0;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Tells remote device to adjust volume. Uses the following values:
+ * <ul>
+ * <li>{@link AudioManager#ADJUST_LOWER}</li>
+ * <li>{@link AudioManager#ADJUST_RAISE}</li>
+ * <li>{@link AudioManager#ADJUST_MUTE}</li>
+ * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
+ * </ul>
+ *
+ * @param direction One of the supported adjust values.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public void adjustVolume(int direction) {
+ if (DBG) log("adjustVolume(" + direction + ")");
+
+ try {
+ mServiceLock.readLock().lock();
+
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return;
+ }
+
+ if (!isEnabled()) return;
+
+ mService.adjustVolume(direction);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Tells remote device to set an absolute volume.
+ *
+ * @param volume Absolute volume to be set on remote
+ * @hide
+ */
+ public void setVolume(int volume) {
+ if (DBG) Log.d(TAG, "setVolume(" + volume + ")");
+
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return;
+ }
+
+ if (!isEnabled()) return;
+
+ mService.setVolume(volume);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the CustomerId of the device.
+ *
+ * @param device Bluetooth device
+ * @return the CustomerId of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public long getHiSyncId(BluetoothDevice device) {
+ if (VDBG) {
+ log("getCustomerId(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return HI_SYNC_ID_INVALID;
+ }
+
+ if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID;
+
+ return mService.getHiSyncId(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return HI_SYNC_ID_INVALID;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the side of the device.
+ *
+ * @param device Bluetooth device.
+ * @return SIDE_LEFT or SIDE_RIGHT
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getDeviceSide(BluetoothDevice device) {
+ if (VDBG) {
+ log("getDeviceSide(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getDeviceSide(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return SIDE_LEFT;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return SIDE_LEFT;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the mode of the device.
+ *
+ * @param device Bluetooth device
+ * @return MODE_MONAURAL or MODE_BINAURAL
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getDeviceMode(BluetoothDevice device) {
+ if (VDBG) {
+ log("getDeviceMode(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getDeviceMode(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return MODE_MONAURAL;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return MODE_MONAURAL;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service));
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEARING_AID,
+ BluetoothHearingAid.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEARING_AID);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 0e2263f..656188f 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -165,12 +165,19 @@
public static final int OPP = 20;
/**
+ * Hearing Aid Device
+ *
+ * @hide
+ */
+ int HEARING_AID = 21;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- public static final int MAX_PROFILE_ID = 20;
+ int MAX_PROFILE_ID = 21;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 76cb3f5..0a0d214 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -79,6 +79,9 @@
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
+ /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */
+ public static final ParcelUuid HearingAid =
+ ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05");
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index a2991e6..64e9e5d 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -58,7 +58,7 @@
private SQLiteDatabase mDatabase;
private boolean mIsInitializing;
- private final SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
+ private SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
/**
* Create a helper object to create, open, and/or manage a database.
@@ -163,8 +163,7 @@
mName = name;
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
- mOpenParamsBuilder = openParamsBuilder;
- mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
+ setOpenParamsBuilder(openParamsBuilder);
}
/**
@@ -230,6 +229,30 @@
}
/**
+ * Sets configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * <p>Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be set when
+ * opening the database
+ *
+ * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * @throws IllegalStateException if the database is already open
+ */
+ public void setOpenParams(@NonNull SQLiteDatabase.OpenParams openParams) {
+ Preconditions.checkNotNull(openParams);
+ synchronized (this) {
+ if (mDatabase != null && mDatabase.isOpen()) {
+ throw new IllegalStateException(
+ "OpenParams cannot be set after opening the database");
+ }
+ setOpenParamsBuilder(new SQLiteDatabase.OpenParams.Builder(openParams));
+ }
+ }
+
+ private void setOpenParamsBuilder(SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
+ mOpenParamsBuilder = openParamsBuilder;
+ mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
+ }
+
+ /**
* Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
* before it is closed and removed from the pool.
*
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
new file mode 100644
index 0000000..b8fea55
--- /dev/null
+++ b/core/java/android/hardware/OWNERS
@@ -0,0 +1,7 @@
+# Camera
+per-file *Camera* = cychen@google.com
+per-file *Camera* = epeev@google.com
+per-file *Camera* = etalvala@google.com
+per-file *Camera* = shuzhenwang@google.com
+per-file *Camera* = yinchiayeh@google.com
+per-file *Camera* = zhijunhe@google.com
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 3f8eaa9..8502fc4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -341,7 +341,7 @@
*/
@SuppressWarnings({"unchecked"})
public List<CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys() {
- if (mAvailableSessionKeys == null) {
+ if (mAvailablePhysicalRequestKeys == null) {
Object crKey = CaptureRequest.Key.class;
Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
@@ -1790,11 +1790,7 @@
* The respective value of such request key can be obtained by calling
* {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
* individual physical device requests must be built via
- * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.
- * Such extended capture requests can be passed only to
- * {@link CameraCaptureSession#capture } or {@link CameraCaptureSession#captureBurst } and
- * not to {@link CameraCaptureSession#setRepeatingRequest } or
- * {@link CameraCaptureSession#setRepeatingBurst }.</p>
+ * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index fd285ae..72db33f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -863,11 +863,8 @@
* request for a specific physical camera. The settings are chosen
* to be the best options for the specific logical camera device. If
* additional physical camera ids are passed, then they will also use the
- * same settings template. Requests containing individual physical camera
- * settings can be passed only to {@link CameraCaptureSession#capture} or
- * {@link CameraCaptureSession#captureBurst} and not to
- * {@link CameraCaptureSession#setRepeatingRequest} or
- * {@link CameraCaptureSession#setRepeatingBurst}</p>
+ * same settings template. Clients can further modify individual camera
+ * settings by calling {@link CaptureRequest.Builder#setPhysicalCameraKey}.</p>
*
* <p>Individual physical camera settings will only be honored for camera session
* that was initialiazed with corresponding physical camera id output configuration
@@ -896,8 +893,8 @@
* @see #TEMPLATE_STILL_CAPTURE
* @see #TEMPLATE_VIDEO_SNAPSHOT
* @see #TEMPLATE_MANUAL
- * @see CaptureRequest.Builder#setKey
- * @see CaptureRequest.Builder#getKey
+ * @see CaptureRequest.Builder#setPhysicalCameraKey
+ * @see CaptureRequest.Builder#getPhysicalCameraKey
*/
@NonNull
public CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType,
diff --git a/core/java/android/hardware/camera2/OWNERS b/core/java/android/hardware/camera2/OWNERS
new file mode 100644
index 0000000..18acfee
--- /dev/null
+++ b/core/java/android/hardware/camera2/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 6a262e2..8599f47 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -218,6 +218,25 @@
@VisibleForTesting
public IpSecConfig() {}
+ /** Copy constructor */
+ @VisibleForTesting
+ public IpSecConfig(IpSecConfig c) {
+ mMode = c.mMode;
+ mSourceAddress = c.mSourceAddress;
+ mDestinationAddress = c.mDestinationAddress;
+ mNetwork = c.mNetwork;
+ mSpiResourceId = c.mSpiResourceId;
+ mEncryption = c.mEncryption;
+ mAuthentication = c.mAuthentication;
+ mAuthenticatedEncryption = c.mAuthenticatedEncryption;
+ mEncapType = c.mEncapType;
+ mEncapSocketResourceId = c.mEncapSocketResourceId;
+ mEncapRemotePort = c.mEncapRemotePort;
+ mNattKeepaliveInterval = c.mNattKeepaliveInterval;
+ mMarkValue = c.mMarkValue;
+ mMarkMask = c.mMarkMask;
+ }
+
private IpSecConfig(Parcel in) {
mMode = in.readInt();
mSourceAddress = in.readString();
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 38759a9..60e96f9 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -84,9 +84,11 @@
@Retention(RetentionPolicy.SOURCE)
public @interface EncapType {}
- private IpSecTransform(Context context, IpSecConfig config) {
+ /** @hide */
+ @VisibleForTesting
+ public IpSecTransform(Context context, IpSecConfig config) {
mContext = context;
- mConfig = config;
+ mConfig = new IpSecConfig(config);
mResourceId = INVALID_RESOURCE_ID;
}
@@ -143,6 +145,18 @@
}
/**
+ * Equals method used for testing
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static boolean equals(IpSecTransform lhs, IpSecTransform rhs) {
+ if (lhs == null || rhs == null) return (lhs == rhs);
+ return IpSecConfig.equals(lhs.getConfig(), rhs.getConfig())
+ && lhs.mResourceId == rhs.mResourceId;
+ }
+
+ /**
* Deactivate this {@code IpSecTransform} and free allocated resources.
*
* <p>Deactivating a transform while it is still applied to a socket will result in errors on
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index cdee110..228fe7a 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -29,7 +29,13 @@
private static final NativeAllocationRegistry sNativeRegistry;
- /** @hide */
+ /**
+ * Create and initialize a HwBinder object and the native objects
+ * used to allow this to participate in hwbinder transactions.
+ *
+ * @hide
+ */
+ @SystemApi
public HwBinder() {
native_setup();
@@ -44,12 +50,28 @@
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
- /** @hide */
+ /**
+ * Process a hwbinder transaction.
+ *
+ * @param code interface specific code for interface.
+ * @param request parceled transaction
+ * @param reply object to parcel reply into
+ * @param flags transaction flags to be chosen by wire protocol
+ *
+ * @hide
+ */
+ @SystemApi
public abstract void onTransact(
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
- /** @hide */
+ /**
+ * Registers this service with the hwservicemanager.
+ *
+ * @param serviceName instance name of the service
+ * @hide
+ */
+ @SystemApi
public native final void registerService(String serviceName)
throws RemoteException;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 65e9473..5e23932 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -71,6 +71,7 @@
Bundle getUserRestrictions(int userHandle);
boolean hasBaseUserRestriction(String restrictionKey, int userHandle);
boolean hasUserRestriction(in String restrictionKey, int userHandle);
+ boolean hasUserRestrictionOnAnyUser(in String restrictionKey);
void setUserRestriction(String key, boolean value, int userHandle);
void setApplicationRestrictions(in String packageName, in Bundle restrictions,
int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7e7af1a..1856200 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1678,6 +1678,18 @@
}
/**
+ * @hide
+ * Returns whether any user on the device has the given user restriction set.
+ */
+ public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+ try {
+ return mService.hasUserRestrictionOnAnyUser(restrictionKey);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return the serial number for a user. This is a device-unique
* number assigned to that user; if the user is deleted and then a new
* user created, the new users will not be given the same serial number.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1223271..1feb822 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5443,32 +5443,6 @@
*/
public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
- private static final Validator ENABLED_INPUT_METHODS_VALIDATOR = new Validator() {
- @Override
- public boolean validate(String value) {
- if (value == null) {
- return false;
- }
- String[] inputMethods = value.split(":");
- boolean valid = true;
- for (String inputMethod : inputMethods) {
- if (inputMethod.length() == 0) {
- return false;
- }
- String[] subparts = inputMethod.split(";");
- for (String subpart : subparts) {
- // allow either a non negative integer or a ComponentName
- valid |= (NON_NEGATIVE_INTEGER_VALIDATOR.validate(subpart)
- || COMPONENT_NAME_VALIDATOR.validate(subpart));
- }
- if (!valid) {
- return false;
- }
- }
- return valid;
- }
- };
-
/**
* List of system input methods that are currently disabled. This is a string
* containing the IDs of all disabled input methods, each ID separated
@@ -7709,7 +7683,6 @@
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_VR_LISTENERS,
- ENABLED_INPUT_METHODS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
@@ -7815,7 +7788,6 @@
VALIDATORS.put(ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR);
VALIDATORS.put(ENABLED_VR_LISTENERS, ENABLED_VR_LISTENERS_VALIDATOR);
- VALIDATORS.put(ENABLED_INPUT_METHODS, ENABLED_INPUT_METHODS_VALIDATOR);
VALIDATORS.put(TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR);
VALIDATORS.put(TOUCH_EXPLORATION_ENABLED, TOUCH_EXPLORATION_ENABLED_VALIDATOR);
@@ -11382,7 +11354,8 @@
"chained_battery_attribution_enabled";
/**
- * The packages whitelisted to be run in autofill compatibility mode.
+ * The packages whitelisted to be run in autofill compatibility mode. The list
+ * of packages is ":" colon delimited.
*
* @hide
*/
diff --git a/core/java/android/security/IConfirmationPromptCallback.aidl b/core/java/android/security/IConfirmationPromptCallback.aidl
deleted file mode 100644
index 96a1a04..0000000
--- a/core/java/android/security/IConfirmationPromptCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IConfirmationPromptCallback {
- oneway void onConfirmationPromptCompleted(in int result, in byte[] dataThatWasConfirmed);
-}
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
deleted file mode 100644
index 738eb68..0000000
--- a/core/java/android/security/IKeystoreService.aidl
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.OperationResult;
-import android.security.KeystoreArguments;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IKeystoreService {
- int getState(int userId);
- byte[] get(String name, int uid);
- int insert(String name, in byte[] item, int uid, int flags);
- int del(String name, int uid);
- int exist(String name, int uid);
- String[] list(String namePrefix, int uid);
- int reset();
- int onUserPasswordChanged(int userId, String newPassword);
- int lock(int userId);
- int unlock(int userId, String userPassword);
- int isEmpty(int userId);
- int generate(String name, int uid, int keyType, int keySize, int flags,
- in KeystoreArguments args);
- int import_key(String name, in byte[] data, int uid, int flags);
- byte[] sign(String name, in byte[] data);
- int verify(String name, in byte[] data, in byte[] signature);
- byte[] get_pubkey(String name);
- String grant(String name, int granteeUid);
- int ungrant(String name, int granteeUid);
- long getmtime(String name, int uid);
- int is_hardware_backed(String string);
- int clear_uid(long uid);
-
- // Keymaster 0.4 methods
- int addRngEntropy(in byte[] data, int flags);
- int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid,
- int flags, out KeyCharacteristics characteristics);
- int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
- int uid, out KeyCharacteristics characteristics);
- int importKey(String alias, in KeymasterArguments arguments, int format,
- in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
- ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
- in KeymasterBlob appId, int uid);
- OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
- in KeymasterArguments params, in byte[] entropy, int uid);
- OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
- OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature,
- in byte[] entropy);
- int abort(IBinder handle);
- boolean isOperationAuthorized(IBinder token);
- int addAuthToken(in byte[] authToken);
- int onUserAdded(int userId, int parentId);
- int onUserRemoved(int userId);
- int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
- int attestDeviceIds(in KeymasterArguments params, out KeymasterCertificateChain chain);
- int onDeviceOffBody();
- int importWrappedKey(in String wrappedKeyAlias, in byte[] wrappedKey,
- in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
- in long rootSid, in long fingerprintSid,
- out KeyCharacteristics characteristics);
- int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
- in String locale, in int uiOptionsAsFlags);
- int cancelConfirmationPrompt(IBinder listener);
-}
diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl
deleted file mode 100644
index dc8ed50..0000000
--- a/core/java/android/security/KeystoreArguments.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl
deleted file mode 100644
index 1748653..0000000
--- a/core/java/android/security/keymaster/ExportResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable ExportResult cpp_header "keystore/ExportResult.h";
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
deleted file mode 100644
index 32e75ad..0000000
--- a/core/java/android/security/keymaster/KeyCharacteristics.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeyCharacteristics cpp_header "keystore/KeyCharacteristics.h";
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
deleted file mode 100644
index 44d9f09..0000000
--- a/core/java/android/security/keymaster/KeymasterArguments.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterArguments cpp_header "keystore/KeymasterArguments.h";
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
deleted file mode 100644
index 5c5db9e..0000000
--- a/core/java/android/security/keymaster/KeymasterBlob.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterBlob cpp_header "keystore/KeymasterBlob.h";
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
deleted file mode 100644
index ddb5cae..0000000
--- a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterCertificateChain cpp_header "keystore/KeymasterCertificateChain.h";
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
deleted file mode 100644
index db689d4..0000000
--- a/core/java/android/security/keymaster/OperationResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable OperationResult cpp_header "keystore/OperationResult.h";
diff --git a/core/java/android/security/keystore/OWNERS b/core/java/android/security/keystore/OWNERS
new file mode 100644
index 0000000..bb487fb
--- /dev/null
+++ b/core/java/android/security/keystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 7383de7..70c4ec0 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -32,12 +32,12 @@
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.Xml;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -45,7 +45,6 @@
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.Map;
/**
* {@link ServiceInfo} and meta-data about an {@link AutofillService}.
@@ -80,7 +79,7 @@
private final String mSettingsActivity;
@Nullable
- private final Map<String, Long> mCompatibilityPackages;
+ private final ArrayMap<String, Pair<Long, String>> mCompatibilityPackages;
public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
@@ -118,7 +117,7 @@
}
String settingsActivity = null;
- Map<String, Long> compatibilityPackages = null;
+ ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
try {
final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -154,9 +153,10 @@
mCompatibilityPackages = compatibilityPackages;
}
- private Map<String, Long> parseCompatibilityPackages(XmlPullParser parser, Resources resources)
+ private ArrayMap<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
+ Resources resources)
throws IOException, XmlPullParserException {
- Map<String, Long> compatibilityPackages = null;
+ ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
final int outerDepth = parser.getDepth();
int type;
@@ -200,11 +200,13 @@
} else {
maxVersionCode = Long.MAX_VALUE;
}
+ final String urlBarResourceId = cpAttributes.getString(
+ R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
if (compatibilityPackages == null) {
compatibilityPackages = new ArrayMap<>();
}
- compatibilityPackages.put(name, maxVersionCode);
+ compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId));
} finally {
XmlUtils.skipCurrentTag(parser);
if (cpAttributes != null) {
@@ -226,16 +228,21 @@
return mSettingsActivity;
}
+ public ArrayMap<String, Pair<Long, String>> getCompatibilityPackages() {
+ return mCompatibilityPackages;
+ }
+
+ /**
+ * Gets the resource id of the URL bar for a package. Used in compat mode
+ */
+ // TODO: return a list of strings instead
@Nullable
- public boolean isCompatibilityModeRequested(String packageName, long versionCode) {
+ public String getUrlBarResourceId(String packageName) {
if (mCompatibilityPackages == null) {
- return false;
+ return null;
}
- final Long maxVersionCode = mCompatibilityPackages.get(packageName);
- if (maxVersionCode == null) {
- return false;
- }
- return versionCode <= maxVersionCode;
+ final Pair<Long, String> pair = mCompatibilityPackages.get(packageName);
+ return pair == null ? null : pair.second;
}
@Override
diff --git a/core/java/android/service/autofill/DateTransformation.java b/core/java/android/service/autofill/DateTransformation.java
index 4e1425d..ec24a09 100644
--- a/core/java/android/service/autofill/DateTransformation.java
+++ b/core/java/android/service/autofill/DateTransformation.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.icu.text.DateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -30,7 +31,6 @@
import com.android.internal.util.Preconditions;
-import java.text.DateFormat;
import java.util.Date;
/**
diff --git a/core/java/android/service/autofill/DateValueSanitizer.java b/core/java/android/service/autofill/DateValueSanitizer.java
index 0f7b540..4f797f4 100644
--- a/core/java/android/service/autofill/DateValueSanitizer.java
+++ b/core/java/android/service/autofill/DateValueSanitizer.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.icu.text.DateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -28,7 +29,6 @@
import com.android.internal.util.Preconditions;
-import java.text.DateFormat;
import java.util.Date;
/**
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index cda2f4a..535c00b 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -177,30 +177,6 @@
return foundNodes;
}
- /**
- * Finds the {@link ViewNode} that has the requested {@code id}, if any.
- *
- * @hide
- */
- @Nullable public ViewNode findViewNodeByAutofillId(@NonNull AutofillId id) {
- final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
- final int numWindowNodes = mStructure.getWindowNodeCount();
- for (int i = 0; i < numWindowNodes; i++) {
- nodesToProcess.add(mStructure.getWindowNodeAt(i).getRootViewNode());
- }
- while (!nodesToProcess.isEmpty()) {
- final ViewNode node = nodesToProcess.removeFirst();
- if (id.equals(node.getAutofillId())) {
- return node;
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- nodesToProcess.addLast(node.getChildAt(i));
- }
- }
-
- return null;
- }
-
public static final Parcelable.Creator<FillContext> CREATOR =
new Parcelable.Creator<FillContext>() {
@Override
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index dbe4157..6fa5312 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -322,12 +322,6 @@
*/
public static Metrics isBoring(CharSequence text, TextPaint paint,
TextDirectionHeuristic textDir, Metrics metrics) {
- return isBoring(text, null /* precomputed */, paint, textDir, metrics);
- }
-
- /** @hide */
- public static Metrics isBoring(CharSequence text, PrecomputedText precomputed, TextPaint paint,
- TextDirectionHeuristic textDir, Metrics metrics) {
final int textLength = text.length();
if (hasAnyInterestingChars(text, textLength)) {
return null; // There are some interesting characters. Not boring.
@@ -350,17 +344,18 @@
fm.reset();
}
- if (precomputed != null) {
+ TextLine line = TextLine.obtain();
+ line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
+ Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
+ if (text instanceof MeasuredText) {
+ MeasuredText mt = (MeasuredText) text;
// Reaching here means there is only one paragraph.
- MeasuredParagraph mp = precomputed.getMeasuredParagraph(0);
+ MeasuredParagraph mp = mt.getMeasuredParagraph(0);
fm.width = (int) Math.ceil(mp.getWidth(0, mp.getTextLength()));
} else {
- TextLine line = TextLine.obtain();
- line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
- Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
fm.width = (int) Math.ceil(line.metrics(fm));
- TextLine.recycle(line);
}
+ TextLine.recycle(line);
return fm;
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 10444f0..18431ca 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -363,7 +363,7 @@
@JustificationMode int justificationMode,
@Nullable TextUtils.TruncateAt ellipsize,
@IntRange(from = 0) int ellipsizedWidth) {
- super(createEllipsizer(ellipsize, display), null /* precomputed */,
+ super(createEllipsizer(ellipsize, display),
paint, width, align, textDir, spacingmult, spacingadd);
final Builder b = Builder.obtain(base, paint, width)
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index d5d3590..aa97b2a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -245,13 +245,6 @@
protected Layout(CharSequence text, TextPaint paint,
int width, Alignment align, TextDirectionHeuristic textDir,
float spacingMult, float spacingAdd) {
- this(text, null /* precomputed */, paint, width, align, textDir, spacingMult, spacingAdd);
- }
-
- /** @hide */
- protected Layout(CharSequence text, PrecomputedText precomputed, TextPaint paint,
- int width, Alignment align, TextDirectionHeuristic textDir,
- float spacingMult, float spacingAdd) {
if (width < 0)
throw new IllegalArgumentException("Layout: " + width + " < 0");
@@ -266,7 +259,6 @@
}
mText = text;
- mPrecomputed = precomputed;
mPaint = paint;
mWidth = width;
mAlignment = align;
@@ -570,7 +562,7 @@
// XXX: assumes there's nothing additional to be done
canvas.drawText(buf, start, end, x, lbaseline, paint);
} else {
- tl.set(paint, buf, mPrecomputed, start, end, dir, directions, hasTab, tabStops);
+ tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops);
if (justify) {
tl.justify(right - left - indentWidth);
}
@@ -2272,7 +2264,6 @@
}
private CharSequence mText;
- private PrecomputedText mPrecomputed;
private TextPaint mPaint;
private TextPaint mWorkPaint = new TextPaint();
private int mWidth;
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
new file mode 100644
index 0000000..bb7a9e0
--- /dev/null
+++ b/core/java/android/text/MeasuredText.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.util.IntArray;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+
+/**
+ * A text which has already been measured.
+ */
+public class MeasuredText implements Spanned {
+ private static final char LINE_FEED = '\n';
+
+ // The original text.
+ private final @NonNull CharSequence mText;
+
+ // The inclusive start offset of the measuring target.
+ private final @IntRange(from = 0) int mStart;
+
+ // The exclusive end offset of the measuring target.
+ private final @IntRange(from = 0) int mEnd;
+
+ // The TextPaint used for measurement.
+ private final @NonNull TextPaint mPaint;
+
+ // The requested text direction.
+ private final @NonNull TextDirectionHeuristic mTextDir;
+
+ // The measured paragraph texts.
+ private final @NonNull MeasuredParagraph[] mMeasuredParagraphs;
+
+ // The sorted paragraph end offsets.
+ private final @NonNull int[] mParagraphBreakPoints;
+
+ // The break strategy for this measured text.
+ private final @Layout.BreakStrategy int mBreakStrategy;
+
+ // The hyphenation frequency for this measured text.
+ private final @Layout.HyphenationFrequency int mHyphenationFrequency;
+
+ /**
+ * A Builder for MeasuredText
+ */
+ public static final class Builder {
+ // Mandatory parameters.
+ private final @NonNull CharSequence mText;
+ private final @NonNull TextPaint mPaint;
+
+ // Members to be updated by setters.
+ private @IntRange(from = 0) int mStart;
+ private @IntRange(from = 0) int mEnd;
+ private TextDirectionHeuristic mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
+ private @Layout.BreakStrategy int mBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
+ private @Layout.HyphenationFrequency int mHyphenationFrequency =
+ Layout.HYPHENATION_FREQUENCY_NORMAL;
+
+
+ /**
+ * Builder constructor
+ *
+ * @param text The text to be measured.
+ * @param paint The paint to be used for drawing.
+ */
+ public Builder(@NonNull CharSequence text, @NonNull TextPaint paint) {
+ Preconditions.checkNotNull(text);
+ Preconditions.checkNotNull(paint);
+
+ mText = text;
+ mPaint = paint;
+ mStart = 0;
+ mEnd = text.length();
+ }
+
+ /**
+ * Set the range of measuring target.
+ *
+ * @param start The measuring target start offset in the text.
+ * @param end The measuring target end offset in the text.
+ */
+ public @NonNull Builder setRange(@IntRange(from = 0) int start,
+ @IntRange(from = 0) int end) {
+ Preconditions.checkArgumentInRange(start, 0, mText.length(), "start");
+ Preconditions.checkArgumentInRange(end, 0, mText.length(), "end");
+ Preconditions.checkArgument(start <= end, "The range is reversed.");
+
+ mStart = start;
+ mEnd = end;
+ return this;
+ }
+
+ /**
+ * Set the text direction heuristic
+ *
+ * The default value is {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}.
+ *
+ * @param textDir The text direction heuristic for resolving bidi behavior.
+ * @return this builder, useful for chaining.
+ */
+ public @NonNull Builder setTextDirection(@NonNull TextDirectionHeuristic textDir) {
+ Preconditions.checkNotNull(textDir);
+ mTextDir = textDir;
+ return this;
+ }
+
+ /**
+ * Set the break strategy
+ *
+ * The default value is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}.
+ *
+ * @param breakStrategy The break strategy.
+ * @return this builder, useful for chaining.
+ */
+ public @NonNull Builder setBreakStrategy(@Layout.BreakStrategy int breakStrategy) {
+ mBreakStrategy = breakStrategy;
+ return this;
+ }
+
+ /**
+ * Set the hyphenation frequency
+ *
+ * The default value is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}.
+ *
+ * @param hyphenationFrequency The hyphenation frequency.
+ * @return this builder, useful for chaining.
+ */
+ public @NonNull Builder setHyphenationFrequency(
+ @Layout.HyphenationFrequency int hyphenationFrequency) {
+ mHyphenationFrequency = hyphenationFrequency;
+ return this;
+ }
+
+ /**
+ * Build the measured text
+ *
+ * @return the measured text.
+ */
+ public @NonNull MeasuredText build() {
+ return build(true /* build full layout result */);
+ }
+
+ /** @hide */
+ public @NonNull MeasuredText build(boolean computeLayout) {
+ final boolean needHyphenation = mBreakStrategy != Layout.BREAK_STRATEGY_SIMPLE
+ && mHyphenationFrequency != Layout.HYPHENATION_FREQUENCY_NONE;
+
+ final IntArray paragraphEnds = new IntArray();
+ final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>();
+
+ int paraEnd = 0;
+ for (int paraStart = mStart; paraStart < mEnd; paraStart = paraEnd) {
+ paraEnd = TextUtils.indexOf(mText, LINE_FEED, paraStart, mEnd);
+ if (paraEnd < 0) {
+ // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
+ // end.
+ paraEnd = mEnd;
+ } else {
+ paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph.
+ }
+
+ paragraphEnds.add(paraEnd);
+ measuredTexts.add(MeasuredParagraph.buildForStaticLayout(
+ mPaint, mText, paraStart, paraEnd, mTextDir, needHyphenation,
+ computeLayout, null /* no recycle */));
+ }
+
+ return new MeasuredText(mText, mStart, mEnd, mPaint, mTextDir, mBreakStrategy,
+ mHyphenationFrequency, measuredTexts.toArray(
+ new MeasuredParagraph[measuredTexts.size()]),
+ paragraphEnds.toArray());
+ }
+ };
+
+ // Use MeasuredText.Builder instead.
+ private MeasuredText(@NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextPaint paint,
+ @NonNull TextDirectionHeuristic textDir,
+ @Layout.BreakStrategy int breakStrategy,
+ @Layout.HyphenationFrequency int frequency,
+ @NonNull MeasuredParagraph[] measuredTexts,
+ @NonNull int[] paragraphBreakPoints) {
+ mText = text;
+ mStart = start;
+ mEnd = end;
+ // Copy the paint so that we can keep the reference of typeface in native layout result.
+ mPaint = new TextPaint(paint);
+ mMeasuredParagraphs = measuredTexts;
+ mParagraphBreakPoints = paragraphBreakPoints;
+ mTextDir = textDir;
+ mBreakStrategy = breakStrategy;
+ mHyphenationFrequency = frequency;
+ }
+
+ /**
+ * Return the underlying text.
+ */
+ public @NonNull CharSequence getText() {
+ return mText;
+ }
+
+ /**
+ * Returns the inclusive start offset of measured region.
+ */
+ public @IntRange(from = 0) int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Returns the exclusive end offset of measured region.
+ */
+ public @IntRange(from = 0) int getEnd() {
+ return mEnd;
+ }
+
+ /**
+ * Returns the text direction associated with char sequence.
+ */
+ public @NonNull TextDirectionHeuristic getTextDir() {
+ return mTextDir;
+ }
+
+ /**
+ * Returns the paint used to measure this text.
+ */
+ public @NonNull TextPaint getPaint() {
+ return mPaint;
+ }
+
+ /**
+ * Returns the length of the paragraph of this text.
+ */
+ public @IntRange(from = 0) int getParagraphCount() {
+ return mParagraphBreakPoints.length;
+ }
+
+ /**
+ * Returns the paragraph start offset of the text.
+ */
+ public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) {
+ Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
+ return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1];
+ }
+
+ /**
+ * Returns the paragraph end offset of the text.
+ */
+ public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) {
+ Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
+ return mParagraphBreakPoints[paraIndex];
+ }
+
+ /** @hide */
+ public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) {
+ return mMeasuredParagraphs[paraIndex];
+ }
+
+ /**
+ * Returns the break strategy for this text.
+ */
+ public @Layout.BreakStrategy int getBreakStrategy() {
+ return mBreakStrategy;
+ }
+
+ /**
+ * Returns the hyphenation frequency for this text.
+ */
+ public @Layout.HyphenationFrequency int getHyphenationFrequency() {
+ return mHyphenationFrequency;
+ }
+
+ /**
+ * Returns true if the given TextPaint gives the same result of text layout for this text.
+ * @hide
+ */
+ public boolean canUseMeasuredResult(@NonNull TextPaint paint) {
+ return mPaint.getTextSize() == paint.getTextSize()
+ && mPaint.getTextSkewX() == paint.getTextSkewX()
+ && mPaint.getTextScaleX() == paint.getTextScaleX()
+ && mPaint.getLetterSpacing() == paint.getLetterSpacing()
+ && mPaint.getWordSpacing() == paint.getWordSpacing()
+ && mPaint.getFlags() == paint.getFlags() // Maybe not all flag affects text layout.
+ && mPaint.getTextLocales() == paint.getTextLocales() // need to be equals?
+ && mPaint.getFontVariationSettings() == paint.getFontVariationSettings()
+ && mPaint.getTypeface() == paint.getTypeface()
+ && TextUtils.equals(mPaint.getFontFeatureSettings(), paint.getFontFeatureSettings());
+ }
+
+ /** @hide */
+ public int findParaIndex(@IntRange(from = 0) int pos) {
+ // TODO: Maybe good to remove paragraph concept from MeasuredText and add substring layout
+ // support to StaticLayout.
+ for (int i = 0; i < mParagraphBreakPoints.length; ++i) {
+ if (pos < mParagraphBreakPoints[i]) {
+ return i;
+ }
+ }
+ throw new IndexOutOfBoundsException(
+ "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1]
+ + ", gave " + pos);
+ }
+
+ /** @hide */
+ public float getWidth(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
+ final int paraIndex = findParaIndex(start);
+ final int paraStart = getParagraphStart(paraIndex);
+ final int paraEnd = getParagraphEnd(paraIndex);
+ if (start < paraStart || paraEnd < end) {
+ throw new RuntimeException("Cannot measured across the paragraph:"
+ + "para: (" + paraStart + ", " + paraEnd + "), "
+ + "request: (" + start + ", " + end + ")");
+ }
+ return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart);
+ }
+
+ /**
+ * Returns the size of native MeasuredText memory usage
+ *
+ * Note that this may not be aculate. Must be used only for testing purposes.
+ * @hide
+ */
+ public int getMemoryUsage() {
+ int r = 0;
+ for (int i = 0; i < getParagraphCount(); ++i) {
+ r += getMeasuredParagraph(i).getMemoryUsage();
+ }
+ return r;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // Spanned overrides
+ //
+ // Just proxy for underlying mText if appropriate.
+
+ @Override
+ public <T> T[] getSpans(int start, int end, Class<T> type) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpans(start, end, type);
+ } else {
+ return ArrayUtils.emptyArray(type);
+ }
+ }
+
+ @Override
+ public int getSpanStart(Object tag) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpanStart(tag);
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int getSpanEnd(Object tag) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpanEnd(tag);
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int getSpanFlags(Object tag) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).getSpanFlags(tag);
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int nextSpanTransition(int start, int limit, Class type) {
+ if (mText instanceof Spanned) {
+ return ((Spanned) mText).nextSpanTransition(start, limit, type);
+ } else {
+ return mText.length();
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // CharSequence overrides.
+ //
+ // Just proxy for underlying mText.
+
+ @Override
+ public int length() {
+ return mText.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ // TODO: Should this be index + mStart ?
+ return mText.charAt(index);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ // TODO: return MeasuredText.
+ // TODO: Should this be index + mStart, end + mStart ?
+ return mText.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return mText.toString();
+ }
+}
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
deleted file mode 100644
index 39fc2bd..0000000
--- a/core/java/android/text/PrecomputedText.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.util.IntArray;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.ArrayList;
-
-/**
- * A text which has the character metrics data
- *
- * This text holds a part of the text layout result. You can accelerate
- * {@link android.widget.TextView} or {@link StaticLayout} by using this text.
- *
- * <pre>
- * Example of background measurement.
- * <code>
- * void asyncSetText(final TextView textView, final String expensiveLongString, Handler handler) {
- * final PrecomputedText.Params params = textView.getTextParams();
- * handler.post(() -> {
- * final PrecomputedText precomputedText
- * = PrecomputedText.create(expensiveLongString, params);
- * textView.post(() -> {
- * textView.setPrecomputedTextOrThrow(precomputedText);
- * });
- * });
- * }
- * </code>
- * </pre>
- *
- * Note that the {@link PrecomputedText} created from different parameters of the target
- * {@link android.widget.TextView} will be rejected internally and compute the text layout again
- * with the current {@link android.widget.TextView} parameters.
- */
-public class PrecomputedText {
- private static final char LINE_FEED = '\n';
-
- /**
- * The information required for building {@link PrecomputedText}.
- *
- * Contains information required for precomputing text measurement metadata, so it can be done
- * in isolation of a {@link android.widget.TextView} or {@link StaticLayout}, when final layout
- * constraints are not known.
- */
- public static class Params {
- // The TextPaint used for measurement.
- private final @NonNull TextPaint mPaint;
-
- // The requested text direction.
- private final @NonNull TextDirectionHeuristic mTextDir;
-
- // The break strategy for this measured text.
- private final @Layout.BreakStrategy int mBreakStrategy;
-
- // The hyphenation frequency for this measured text.
- private final @Layout.HyphenationFrequency int mHyphenationFrequency;
-
- /**
- * A builder for creating {@link Params}.
- */
- public static class Builder {
- // The TextPaint used for measurement.
- private final @NonNull TextPaint mPaint;
-
- // The requested text direction.
- private TextDirectionHeuristic mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
-
- // The break strategy for this measured text.
- private @Layout.BreakStrategy int mBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
-
- // The hyphenation frequency for this measured text.
- private @Layout.HyphenationFrequency int mHyphenationFrequency =
- Layout.HYPHENATION_FREQUENCY_NORMAL;
-
- /**
- * Builder constructor
- *
- * @param paint The paint to be used for drawing
- */
- public Builder(@NonNull TextPaint paint) {
- mPaint = paint;
- }
-
- /**
- * Set the line break strategy
- *
- * The default value is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}.
- *
- * @param strategy The break strategy
- * @return this builder, useful for chaining
- */
- public Builder setBreakStrategy(@Layout.BreakStrategy int strategy) {
- mBreakStrategy = strategy;
- return this;
- }
-
- /**
- * Set the hyphenation frequency
- *
- * The default value is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}.
- *
- * @param frequency The hyphenation frequency
- * @return this builder, useful for chaining
- */
- public Builder setHyphenationFrequency(@Layout.HyphenationFrequency int frequency) {
- mHyphenationFrequency = frequency;
- return this;
- }
-
- /**
- * Set the text direction heuristic
- *
- * The default value is {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}.
- *
- * @param textDir The text direction heuristic for resolving bidi behavior
- * @return this builder, useful for chaining
- */
- public Builder setTextDirection(@NonNull TextDirectionHeuristic textDir) {
- mTextDir = textDir;
- return this;
- }
-
- /**
- * Build the {@link Params}
- *
- * @return the layout parameter
- */
- public @NonNull Params build() {
- return new Params(mPaint, mTextDir, mBreakStrategy, mHyphenationFrequency);
- }
- }
-
- // Use Builder instead.
- /** @hide */
- public Params(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir,
- @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) {
- mPaint = paint;
- mTextDir = textDir;
- mBreakStrategy = strategy;
- mHyphenationFrequency = frequency;
- }
-
- /**
- * Returns the {@link TextPaint} for this text
- *
- * @return A {@link TextPaint}
- */
- public @NonNull TextPaint getTextPaint() {
- return mPaint;
- }
-
- /**
- * Returns the {@link TextDirectionHeuristic} for this text
- *
- * @return A {@link TextDirectionHeuristic}
- */
- public @NonNull TextDirectionHeuristic getTextDirection() {
- return mTextDir;
- }
-
- /**
- * Returns the break strategy for this text
- *
- * @return A line break strategy
- */
- public @Layout.BreakStrategy int getBreakStrategy() {
- return mBreakStrategy;
- }
-
- /**
- * Returns the hyphenation frequency for this text
- *
- * @return A hyphenation frequency
- */
- public @Layout.HyphenationFrequency int getHyphenationFrequency() {
- return mHyphenationFrequency;
- }
-
- private boolean sameTextMetricsInternal(@NonNull TextPaint paint,
- @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy,
- @Layout.HyphenationFrequency int frequency) {
- return mTextDir == textDir
- && mBreakStrategy == strategy
- && mHyphenationFrequency == frequency
- && mPaint.equalsForTextMeasurement(paint);
- }
-
- /**
- * Check if the same text layout.
- *
- * @return true if this and the given param result in the same text layout
- */
- public boolean sameTextMetrics(@NonNull Params param) {
- return sameTextMetricsInternal(param.mPaint, param.mTextDir, param.mBreakStrategy,
- param.mHyphenationFrequency);
- }
- };
-
- // The original text.
- private final @NonNull CharSequence mText;
-
- // The inclusive start offset of the measuring target.
- private final @IntRange(from = 0) int mStart;
-
- // The exclusive end offset of the measuring target.
- private final @IntRange(from = 0) int mEnd;
-
- private final @NonNull Params mParams;
-
- // The measured paragraph texts.
- private final @NonNull MeasuredParagraph[] mMeasuredParagraphs;
-
- // The sorted paragraph end offsets.
- private final @NonNull int[] mParagraphBreakPoints;
-
- /**
- * Create a new {@link PrecomputedText} which will pre-compute text measurement and glyph
- * positioning information.
- * <p>
- * This can be expensive, so computing this on a background thread before your text will be
- * presented can save work on the UI thread.
- * </p>
- *
- * @param text The text to be measured
- * @param param Parameters that define how text will be precomputed
- * @return A {@link PrecomputedText}
- */
- public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params param) {
- return createInternal(text, param, 0, text.length(), true /* compute full Layout */);
- }
-
-
- /** @hide */
- public static PrecomputedText createWidthOnly(@NonNull CharSequence text, @NonNull Params param,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end) {
- return createInternal(text, param, start, end, false /* compute width only */);
- }
-
- private static PrecomputedText createInternal(@NonNull CharSequence text, @NonNull Params param,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean computeLayout) {
- Preconditions.checkNotNull(text);
- Preconditions.checkNotNull(param);
- final boolean needHyphenation = param.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
- && param.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
-
- final IntArray paragraphEnds = new IntArray();
- final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>();
-
- int paraEnd = 0;
- for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
- paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
- if (paraEnd < 0) {
- // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
- // end.
- paraEnd = end;
- } else {
- paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph.
- }
-
- paragraphEnds.add(paraEnd);
- measuredTexts.add(MeasuredParagraph.buildForStaticLayout(
- param.getTextPaint(), text, paraStart, paraEnd, param.getTextDirection(),
- needHyphenation, computeLayout, null /* no recycle */));
- }
-
- return new PrecomputedText(text, start, end, param,
- measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]),
- paragraphEnds.toArray());
- }
-
- // Use PrecomputedText.create instead.
- private PrecomputedText(@NonNull CharSequence text, @IntRange(from = 0) int start,
- @IntRange(from = 0) int end, @NonNull Params param,
- @NonNull MeasuredParagraph[] measuredTexts, @NonNull int[] paragraphBreakPoints) {
- mText = TextUtils.stringOrSpannedString(text);
- mStart = start;
- mEnd = end;
- mParams = param;
- mMeasuredParagraphs = measuredTexts;
- mParagraphBreakPoints = paragraphBreakPoints;
- }
-
- /**
- * Return the underlying text.
- */
- public @NonNull CharSequence getText() {
- return mText;
- }
-
- /**
- * Returns the inclusive start offset of measured region.
- * @hide
- */
- public @IntRange(from = 0) int getStart() {
- return mStart;
- }
-
- /**
- * Returns the exclusive end offset of measured region.
- * @hide
- */
- public @IntRange(from = 0) int getEnd() {
- return mEnd;
- }
-
- /**
- * Returns the layout parameters used to measure this text.
- */
- public @NonNull Params getParams() {
- return mParams;
- }
-
- /**
- * Returns the length of the paragraph of this text.
- */
- public @IntRange(from = 0) int getParagraphCount() {
- return mParagraphBreakPoints.length;
- }
-
- /**
- * Returns the paragraph start offset of the text.
- */
- public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) {
- Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
- return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1];
- }
-
- /**
- * Returns the paragraph end offset of the text.
- */
- public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) {
- Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex");
- return mParagraphBreakPoints[paraIndex];
- }
-
- /** @hide */
- public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) {
- return mMeasuredParagraphs[paraIndex];
- }
-
- /**
- * Returns true if the given TextPaint gives the same result of text layout for this text.
- * @hide
- */
- public boolean canUseMeasuredResult(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
- @NonNull TextDirectionHeuristic textDir, @NonNull TextPaint paint,
- @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) {
- final TextPaint mtPaint = mParams.getTextPaint();
- return mStart == start
- && mEnd == end
- && mParams.sameTextMetricsInternal(paint, textDir, strategy, frequency);
- }
-
- /** @hide */
- public int findParaIndex(@IntRange(from = 0) int pos) {
- // TODO: Maybe good to remove paragraph concept from PrecomputedText and add substring
- // layout support to StaticLayout.
- for (int i = 0; i < mParagraphBreakPoints.length; ++i) {
- if (pos < mParagraphBreakPoints[i]) {
- return i;
- }
- }
- throw new IndexOutOfBoundsException(
- "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1]
- + ", gave " + pos);
- }
-
- /** @hide */
- public float getWidth(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
- final int paraIndex = findParaIndex(start);
- final int paraStart = getParagraphStart(paraIndex);
- final int paraEnd = getParagraphEnd(paraIndex);
- if (start < paraStart || paraEnd < end) {
- throw new RuntimeException("Cannot measured across the paragraph:"
- + "para: (" + paraStart + ", " + paraEnd + "), "
- + "request: (" + start + ", " + end + ")");
- }
- return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart);
- }
-
- /**
- * Returns the size of native PrecomputedText memory usage
- *
- * Note that this is not guaranteed to be accurate. Must be used only for testing purposes.
- * @hide
- */
- public int getMemoryUsage() {
- int r = 0;
- for (int i = 0; i < getParagraphCount(); ++i) {
- r += getMeasuredParagraph(i).getMemoryUsage();
- }
- return r;
- }
-}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 5869802..e62f421 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -78,23 +78,6 @@
/**
* Obtain a builder for constructing StaticLayout objects.
*
- * @param source The precomputed text.
- * @param start The index of the start of the text
- * @param end The index + 1 of the end of the text
- * @param paint The base paint used for layout
- * @param width The width in pixels
- * @return a builder object used for constructing the StaticLayout
- */
- @NonNull
- public static Builder obtain(@NonNull PrecomputedText source, @IntRange(from = 0) int start,
- @IntRange(from = 0) int end, @NonNull TextPaint paint,
- @IntRange(from = 0) int width) {
- return obtain(source.getText(), source, start, end, paint, width);
- }
-
- /**
- * Obtain a builder for constructing StaticLayout objects.
- *
* @param source The text to be laid out, optionally with spans
* @param start The index of the start of the text
* @param end The index + 1 of the end of the text
@@ -106,12 +89,6 @@
public static Builder obtain(@NonNull CharSequence source, @IntRange(from = 0) int start,
@IntRange(from = 0) int end, @NonNull TextPaint paint,
@IntRange(from = 0) int width) {
- return obtain(source, null, start, end, paint, width);
- }
-
- private static Builder obtain(@NonNull CharSequence source, @Nullable PrecomputedText text,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end,
- @NonNull TextPaint paint, @IntRange(from = 0) int width) {
Builder b = sPool.acquire();
if (b == null) {
b = new Builder();
@@ -119,7 +96,6 @@
// set default initial values
b.mText = source;
- b.mPrecomputed = text;
b.mStart = start;
b.mEnd = end;
b.mPaint = paint;
@@ -452,7 +428,6 @@
}
private CharSequence mText;
- private PrecomputedText mPrecomputed;
private int mStart;
private int mEnd;
private TextPaint mPaint;
@@ -515,7 +490,7 @@
float spacingmult, float spacingadd,
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
- this(source, null /* precomputed */, bufstart, bufend, paint, outerwidth, align,
+ this(source, bufstart, bufend, paint, outerwidth, align,
TextDirectionHeuristics.FIRSTSTRONG_LTR,
spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE);
}
@@ -525,16 +500,7 @@
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
- public StaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint,
- int outerwidth, Alignment align, TextDirectionHeuristic textDir,
- float spacingmult, float spacingadd, boolean includepad,
- TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) {
- this(source, null /* precomputed */, bufstart, bufend, paint, outerwidth, align, textDir,
- spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, maxLines);
- }
-
- /** @hide */
- public StaticLayout(CharSequence source, PrecomputedText precomputed, int bufstart, int bufend,
+ public StaticLayout(CharSequence source, int bufstart, int bufend,
TextPaint paint, int outerwidth,
Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
@@ -545,7 +511,6 @@
: (source instanceof Spanned)
? new SpannedEllipsizer(source)
: new Ellipsizer(source),
- (ellipsize == null) ? precomputed : null,
paint, outerwidth, align, textDir, spacingmult, spacingadd);
Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth)
@@ -686,20 +651,43 @@
b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
indents, mLeftPaddings, mRightPaddings);
- PrecomputedText measured = null;
- final Spanned spanned = (b.mText instanceof Spanned) ? (Spanned) b.mText : null;
- if (b.mPrecomputed != null) {
- if (b.mPrecomputed.canUseMeasuredResult(bufStart, bufEnd, textDir, paint,
- b.mBreakStrategy, b.mHyphenationFrequency)) {
- measured = b.mPrecomputed;
+ MeasuredText measured = null;
+ final Spanned spanned;
+ final boolean canUseMeasuredText;
+ if (source instanceof MeasuredText) {
+ measured = (MeasuredText) source;
+
+ if (bufStart != measured.getStart() || bufEnd != measured.getEnd()) {
+ // The buffer position has changed. Re-measure here.
+ canUseMeasuredText = false;
+ } else if (b.mBreakStrategy != measured.getBreakStrategy()
+ || b.mHyphenationFrequency != measured.getHyphenationFrequency()) {
+ // The computed hyphenation pieces may not be able to used. Re-measure it.
+ canUseMeasuredText = false;
+ } else {
+ // We can use measured information.
+ canUseMeasuredText = true;
}
- }
- if (measured == null) {
- final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir,
- b.mBreakStrategy, b.mHyphenationFrequency);
- measured = PrecomputedText.createWidthOnly(source, param, bufStart, bufEnd);
+ } else {
+ canUseMeasuredText = false;
}
+ if (!canUseMeasuredText) {
+ measured = new MeasuredText.Builder(source, paint)
+ .setRange(bufStart, bufEnd)
+ .setTextDirection(textDir)
+ .setBreakStrategy(b.mBreakStrategy)
+ .setHyphenationFrequency(b.mHyphenationFrequency)
+ .build(false /* full layout is not necessary for line breaking */);
+ spanned = (source instanceof Spanned) ? (Spanned) source : null;
+ } else {
+ final CharSequence original = measured.getText();
+ spanned = (original instanceof Spanned) ? (Spanned) original : null;
+ // Overwrite with the one when measured.
+ // TODO: Give an option for developer not to overwrite and measure again here?
+ textDir = measured.getTextDir();
+ paint = measured.getPaint();
+ }
try {
for (int paraIndex = 0; paraIndex < measured.getParagraphCount(); paraIndex++) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index be5bb4d..55367dc 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -16,7 +16,6 @@
package android.text;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Canvas;
@@ -61,7 +60,7 @@
private char[] mChars;
private boolean mCharsValid;
private Spanned mSpanned;
- private PrecomputedText mComputed;
+ private MeasuredText mMeasured;
// Additional width of whitespace for justification. This value is per whitespace, thus
// the line width will increase by mAddedWidth x (number of stretchable whitespaces).
@@ -120,7 +119,7 @@
tl.mSpanned = null;
tl.mTabs = null;
tl.mChars = null;
- tl.mComputed = null;
+ tl.mMeasured = null;
tl.mMetricAffectingSpanSpanSet.recycle();
tl.mCharacterStyleSpanSet.recycle();
@@ -150,31 +149,10 @@
* @param tabStops the tabStops. Can be null.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void set(TextPaint paint, CharSequence text, int start,
- int limit, int dir, Directions directions, boolean hasTabs, TabStops tabStops) {
- set(paint, text, null, start, limit, dir, directions, hasTabs, tabStops);
- }
-
- /**
- * Initializes a TextLine and prepares it for use.
- *
- * @param paint the base paint for the line
- * @param text the text, can be Styled
- * @param precomputed the precomputed text
- * @param start the start of the line relative to the text
- * @param limit the limit of the line relative to the text
- * @param dir the paragraph direction of this line
- * @param directions the directions information of this line
- * @param hasTabs true if the line might contain tabs
- * @param tabStops the tabStops.
- */
- public void set(@NonNull TextPaint paint, @NonNull CharSequence text,
- @Nullable PrecomputedText precomputed, @IntRange(from = 0) int start,
- @IntRange(from = 0) int limit, int dir, @NonNull Directions directions, boolean hasTabs,
- @Nullable TabStops tabStops) {
+ public void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
+ Directions directions, boolean hasTabs, TabStops tabStops) {
mPaint = paint;
mText = text;
- mComputed = precomputed;
mStart = start;
mLen = limit - start;
mDir = dir;
@@ -192,6 +170,14 @@
hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0;
}
+ mMeasured = null;
+ if (text instanceof MeasuredText) {
+ MeasuredText mt = (MeasuredText) text;
+ if (mt.canUseMeasuredResult(paint)) {
+ mMeasured = mt;
+ }
+ }
+
mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
if (mCharsValid) {
@@ -760,12 +746,12 @@
return wp.getRunAdvance(mChars, start, end, contextStart, contextEnd, runIsRtl, offset);
} else {
final int delta = mStart;
- if (mComputed == null) {
+ if (mMeasured == null) {
// TODO: Enable measured getRunAdvance for ReplacementSpan and RTL text.
return wp.getRunAdvance(mText, delta + start, delta + end,
delta + contextStart, delta + contextEnd, runIsRtl, delta + offset);
} else {
- return mComputed.getWidth(start + delta, end + delta);
+ return mMeasured.getWidth(start + delta, end + delta);
}
}
}
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index da7387f..1a397b3 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -86,4 +86,16 @@
while (t.getCause() != null) t = t.getCause();
return t;
}
-}
+
+ /**
+ * Appends {@code cause} at the end of the causal chain of {@code t}
+ *
+ * @return {@code t} for convenience
+ */
+ public static @NonNull Throwable appendCause(@NonNull Throwable t, @Nullable Throwable cause) {
+ if (cause != null) {
+ getRootCause(t).initCause(cause);
+ }
+ return t;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 9b0489c..f9454d9 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -18,9 +18,11 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import java.util.Arrays;
+
import libcore.util.EmptyArray;
+import java.util.Arrays;
+
/**
* Implements a growing array of long primitives.
*
@@ -216,4 +218,17 @@
throw new ArrayIndexOutOfBoundsException(mSize, index);
}
}
+
+ /**
+ * Test if each element of {@code a} equals corresponding element from {@code b}
+ */
+ public static boolean elementsEqual(LongArray a, LongArray b) {
+ if (a.mSize != b.mSize) return false;
+ for (int i = 0; i < a.mSize; i++) {
+ if (a.get(i) != b.get(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
new file mode 100644
index 0000000..86ed122
--- /dev/null
+++ b/core/java/android/util/OWNERS
@@ -0,0 +1,2 @@
+per-file FeatureFlagUtils.java = sbasi@google.com
+per-file FeatureFlagUtils.java = zhfan@google.com
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index 4805318..3350f3e 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -34,7 +34,7 @@
*/
public static boolean logStart(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__START);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__START);
return true;
}
return false;
@@ -48,7 +48,7 @@
*/
public static boolean logStop(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__STOP);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__STOP);
return true;
}
return false;
@@ -62,7 +62,8 @@
*/
public static boolean logEvent(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__UNSPECIFIED);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label,
+ APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
return true;
}
return false;
diff --git a/core/java/android/view/RecordingCanvas.java b/core/java/android/view/RecordingCanvas.java
index fc7d828..fbb862b 100644
--- a/core/java/android/view/RecordingCanvas.java
+++ b/core/java/android/view/RecordingCanvas.java
@@ -34,7 +34,7 @@
import android.graphics.RectF;
import android.graphics.TemporaryBuffer;
import android.text.GraphicsOperations;
-import android.text.PrecomputedText;
+import android.text.MeasuredText;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
@@ -507,8 +507,8 @@
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
long measuredTextPtr = 0;
int measuredTextOffset = 0;
- if (text instanceof PrecomputedText) {
- PrecomputedText mt = (PrecomputedText) text;
+ if (text instanceof MeasuredText) {
+ MeasuredText mt = (MeasuredText) text;
int paraIndex = mt.findParaIndex(start);
if (end <= mt.getParagraphEnd(paraIndex)) {
// Only support if the target is in the same paragraph.
@@ -641,7 +641,7 @@
@FastNative
private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
- long nativePrecomputedText, int measuredTextOffset);
+ long nativeMeasuredText, int measuredTextOffset);
@FastNative
private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index c4a7160..d26a2f6 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -158,7 +158,7 @@
}
private void applyInterpolator() {
- if (mInterpolator == null) return;
+ if (mInterpolator == null || mNativePtr == null) return;
long ni;
if (isNativeInterpolator(mInterpolator)) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 370c97e..e50d40e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -331,6 +331,7 @@
private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
private static final int FLAG_DUMP_RESET = 1 << 1;
+ private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS;
@IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
FLAG_DUMP_FRAMESTATS,
@@ -636,7 +637,10 @@
*/
void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
pw.flush();
- int flags = 0;
+ // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything.
+ // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only
+ // dump the summary information
+ int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0;
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case "framestats":
@@ -645,6 +649,9 @@
case "reset":
flags |= FLAG_DUMP_RESET;
break;
+ case "-a": // magic option passed when dumping a bugreport.
+ flags = FLAG_DUMP_ALL;
+ break;
}
}
nDumpProfileInfo(mNativeProxy, fd, flags);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 417a725..5b1dd5c 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3203,7 +3203,7 @@
fieldIndex++;
if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex);
fieldIndex++;
- if (!Objects.equals(mChildNodeIds, DEFAULT.mChildNodeIds)) {
+ if (!LongArray.elementsEqual(mChildNodeIds, DEFAULT.mChildNodeIds)) {
nonDefaultFields |= bitAt(fieldIndex);
}
fieldIndex++;
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 990fbdb..29f8442 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -18,6 +18,7 @@
import android.annotation.AnimRes;
import android.annotation.InterpolatorRes;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -58,14 +59,43 @@
}
};
- /** @hide */
+ /**
+ * Locks AnimationUtils{@link #currentAnimationTimeMillis()} to a fixed value for the current
+ * thread. This is used by {@link android.view.Choreographer} to ensure that all accesses
+ * during a vsync update are synchronized to the timestamp of the vsync.
+ *
+ * It is also exposed to tests to allow for rapid, flake-free headless testing.
+ *
+ * Must be followed by a call to {@link #unlockAnimationClock()} to allow time to
+ * progress. Failing to do this will result in stuck animations, scrolls, and flings.
+ *
+ * Note that time is not allowed to "rewind" and must perpetually flow forward. So the
+ * lock may fail if the time is in the past from a previously returned value, however
+ * time will be frozen for the duration of the lock. The clock is a thread-local, so
+ * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()}, and
+ * {@link #currentAnimationTimeMillis()} are all called on the same thread.
+ *
+ * This is also not reference counted in any way. Any call to {@link #unlockAnimationClock()}
+ * will unlock the clock for everyone on the same thread. It is therefore recommended
+ * for tests to use their own thread to ensure that there is no collision with any existing
+ * {@link android.view.Choreographer} instance.
+ *
+ * @hide
+ * */
+ @TestApi
public static void lockAnimationClock(long vsyncMillis) {
AnimationState state = sAnimationState.get();
state.animationClockLocked = true;
state.currentVsyncTimeMillis = vsyncMillis;
}
- /** @hide */
+ /**
+ * Frees the time lock set in place by {@link #lockAnimationClock(long)}. Must be called
+ * to allow the animation clock to self-update.
+ *
+ * @hide
+ */
+ @TestApi
public static void unlockAnimationClock() {
sAnimationState.get().animationClockLocked = false;
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 8b64bad..41d05a5 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1407,7 +1407,8 @@
mSessionId = mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
- mCallback != null, flags, client.autofillClientGetComponentName());
+ mCallback != null, flags, client.autofillClientGetComponentName(),
+ isCompatibilityModeEnabledLocked());
if (mSessionId != NO_SESSION) {
mState = STATE_ACTIVE;
}
@@ -1474,7 +1475,7 @@
client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, client.autofillClientGetComponentName(),
- mSessionId, action);
+ mSessionId, action, isCompatibilityModeEnabledLocked());
if (newId != mSessionId) {
if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
mSessionId = newId;
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 0018547..56f79ab 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -38,7 +38,7 @@
void removeClient(in IAutoFillManagerClient client, int userId);
int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
- in ComponentName componentName);
+ in ComponentName componentName, boolean compatMode);
FillEventHistory getFillEventHistory();
boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
@@ -46,7 +46,7 @@
int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
boolean hasCallback, int flags, in ComponentName componentName, int sessionId,
- int action);
+ int action, boolean compatMode);
void finishSession(int sessionId, int userId);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f6e771a..5710db3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -80,8 +80,8 @@
import android.text.InputFilter;
import android.text.InputType;
import android.text.Layout;
+import android.text.MeasuredText;
import android.text.ParcelableSpan;
-import android.text.PrecomputedText;
import android.text.Selection;
import android.text.SpanWatcher;
import android.text.Spannable;
@@ -637,7 +637,6 @@
private CharSequence mText;
private CharSequence mTransformed;
private BufferType mBufferType = BufferType.NORMAL;
- private PrecomputedText mPrecomputed;
private CharSequence mHint;
private Layout mHintLayout;
@@ -4086,80 +4085,6 @@
}
/**
- * Gets the parameters for text layout precomputation, for use with {@link PrecomputedText}
- *
- * @return A current {@link PrecomputedText.Params}
- */
- public @NonNull PrecomputedText.Params getTextMetricsParams() {
- return new PrecomputedText.Params(new TextPaint(mTextPaint), getTextDirectionHeuristic(),
- mBreakStrategy, mHyphenationFrequency);
- }
-
- /**
- * Apply the text layout parameter.
- */
- public void setTextMetricsParams(@NonNull PrecomputedText.Params params) {
- mTextPaint.set(params.getTextPaint());
- mTextDir = params.getTextDirection();
- mBreakStrategy = params.getBreakStrategy();
- mHyphenationFrequency = params.getHyphenationFrequency();
- if (mLayout != null) {
- nullLayouts();
- requestLayout();
- invalidate();
- }
- }
-
- /**
- * Sets the precomputed text.
- *
- * If the parameters for the precomputed text is different from current text view parameters,
- * apply the parameteres to the text view too.
- *
- * @param text A precomputed text.
- */
- public void setPrecomputedTextAndParams(@NonNull PrecomputedText text) {
- Preconditions.checkNotNull(text);
- final PrecomputedText.Params params = text.getParams();
- if (!params.sameTextMetrics(getTextMetricsParams())) {
- setTextMetricsParams(params);
- }
- setText(text.getText());
- if (mTransformed != text.getText()) {
- // setText modified given text for some reasons, selection, transformation, etc.
- // Can't use computed result.
- return;
- } else {
- mPrecomputed = text;
- }
- }
-
- /**
- * Sets the precomputed text.
- *
- * If the parameters for the precomputed text is different from current text view parameters,
- * throws {@link IllegalArgumentException}.
- *
- * @param text A precomputed text.
- */
- public void setPrecomputedTextOrThrow(@NonNull PrecomputedText text) {
- Preconditions.checkNotNull(text);
- final PrecomputedText.Params params = text.getParams();
- if (!params.sameTextMetrics(getTextMetricsParams())) {
- throw new IllegalArgumentException(
- "The precomputed configuration is different from this TextView.");
- }
- setText(text.getText());
- if (mTransformed != text.getText()) {
- // setText modified given text for some reasons, selection, transformation, etc.
- // Can't use computed result.
- // TODO: Do we throw an exception here too?
- } else {
- mPrecomputed = text;
- }
- }
-
- /**
* Set justification mode. The default value is {@link Layout#JUSTIFICATION_MODE_NONE}. If the
* last line is too short for justification, the last line will be displayed with the
* alignment set by {@link android.view.View#setTextAlignment}.
@@ -5594,7 +5519,6 @@
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
- mPrecomputed = null;
mTextSetFromXmlOrResourceId = false;
if (text == null) {
text = "";
@@ -5653,7 +5577,7 @@
if (imm != null) imm.restartInput(this);
} else if (type == BufferType.SPANNABLE || mMovement != null) {
text = mSpannableFactory.newSpannable(text);
- } else if (!(text instanceof CharWrapper)) {
+ } else if (!(text instanceof MeasuredText || text instanceof CharWrapper)) {
text = TextUtils.stringOrSpannedString(text);
}
@@ -8320,8 +8244,7 @@
result = builder.build();
} else {
if (boring == UNKNOWN_BORING) {
- boring = BoringLayout.isBoring(mTransformed, mPrecomputed, mTextPaint, mTextDir,
- mBoring);
+ boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
if (boring != null) {
mBoring = boring;
}
@@ -8359,15 +8282,9 @@
}
}
if (result == null) {
- StaticLayout.Builder builder;
- if (mPrecomputed != null) {
- builder = StaticLayout.Builder.obtain(mPrecomputed, 0,
- mPrecomputed.getText().length(), mTextPaint, wantWidth);
- } else {
- builder = StaticLayout.Builder.obtain(mTransformed, 0, mTransformed.length(),
- mTextPaint, wantWidth);
- }
- builder.setAlignment(alignment)
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
+ 0, mTransformed.length(), mTextPaint, wantWidth)
+ .setAlignment(alignment)
.setTextDirection(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
@@ -8494,8 +8411,7 @@
}
if (des < 0) {
- boring = BoringLayout.isBoring(mTransformed, mPrecomputed, mTextPaint, mTextDir,
- mBoring);
+ boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
if (boring != null) {
mBoring = boring;
}
@@ -11780,9 +11696,6 @@
}
/**
- * Returns the current {@link TextDirectionHeuristic}
- *
- * @return A {@link TextDirectionHeuristic}.
* @hide
*/
protected TextDirectionHeuristic getTextDirectionHeuristic() {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eb58b09..6a56f45 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -187,7 +187,7 @@
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
- static final int MSG_UPDATE_WAKELOCKS = 1;
+ static final int MSG_REPORT_CPU_UPDATE_NEEDED = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
static final int MSG_REPORT_CHARGING = 3;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
@@ -273,10 +273,7 @@
public void handleMessage(Message msg) {
BatteryCallback cb = mCallback;
switch (msg.what) {
- case MSG_UPDATE_WAKELOCKS:
- synchronized (BatteryStatsImpl.this) {
- updateCpuTimeLocked();
- }
+ case MSG_REPORT_CPU_UPDATE_NEEDED:
if (cb != null) {
cb.batteryNeedsCpuUpdate();
}
@@ -302,6 +299,10 @@
}
}
+ public void postBatteryNeedsCpuUpdateMsg() {
+ mHandler.sendEmptyMessage(MSG_REPORT_CPU_UPDATE_NEEDED);
+ }
+
/**
* Update per-freq cpu times for all the uids in {@link #mPendingUids}.
*/
@@ -487,6 +488,10 @@
Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCpuSyncDueToSettingChange();
+ Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery,
+ boolean onBatteryScreenOff);
+ Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
+ void cancelCpuSyncDueToWakelockChange();
}
public Handler mHandler;
@@ -1453,12 +1458,10 @@
long mCount;
long mLoadedCount;
long mUnpluggedCount;
- long mPluggedCount;
LongSamplingCounter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
- mPluggedCount = in.readLong();
- mCount = mPluggedCount;
+ mCount = in.readLong();
mLoadedCount = in.readLong();
mUnpluggedCount = in.readLong();
timeBase.add(this);
@@ -1477,16 +1480,15 @@
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedCount = mPluggedCount;
+ mUnpluggedCount = mCount;
}
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mPluggedCount = mCount;
}
public long getCountLocked(int which) {
- long val = mTimeBase.isRunning() ? mCount : mPluggedCount;
+ long val = mCount;
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
@@ -1499,12 +1501,15 @@
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount
+ " mLoadedCount=" + mLoadedCount
- + " mUnpluggedCount=" + mUnpluggedCount
- + " mPluggedCount=" + mPluggedCount);
+ + " mUnpluggedCount=" + mUnpluggedCount);
}
void addCountLocked(long count) {
- if (mTimeBase.isRunning()) {
+ addCountLocked(count, mTimeBase.isRunning());
+ }
+
+ void addCountLocked(long count, boolean isRunning) {
+ if (isRunning) {
mCount += count;
}
}
@@ -1514,7 +1519,7 @@
*/
void reset(boolean detachIfReset) {
mCount = 0;
- mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
+ mLoadedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
@@ -1531,7 +1536,7 @@
void readSummaryFromParcelLocked(Parcel in) {
mLoadedCount = in.readLong();
mCount = mLoadedCount;
- mUnpluggedCount = mPluggedCount = mLoadedCount;
+ mUnpluggedCount = mLoadedCount;
}
}
@@ -3852,9 +3857,6 @@
+ Display.stateToString(screenState)
+ " and battery is " + (unplugged ? "on" : "off"));
}
- updateCpuTimeLocked();
- mExternalSync.scheduleCopyFromAllUidsCpuTimes(mOnBatteryTimeBase.isRunning(),
- mOnBatteryScreenOffTimeBase.isRunning());
mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
if (updateOnBatteryTimeBase) {
@@ -4143,15 +4145,11 @@
}
private void requestWakelockCpuUpdate() {
- if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
- Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
- mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
- }
+ mExternalSync.scheduleCpuSyncDueToWakelockChange(DELAY_UPDATE_WAKELOCKS);
}
private void requestImmediateCpuUpdate() {
- mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
- mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
+ mExternalSync.scheduleCpuSyncDueToWakelockChange(0 /* delayMillis */);
}
public void setRecordAllHistoryLocked(boolean enabled) {
@@ -4554,7 +4552,7 @@
}
public boolean startAddingCpuLocked() {
- mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
+ mExternalSync.cancelCpuSyncDueToWakelockChange();
return mOnBatteryInternal;
}
@@ -4807,6 +4805,8 @@
+ Display.stateToString(state));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
+ mExternalSync.scheduleCpuSyncDueToScreenStateChange(
+ mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning());
if (isScreenOn(state)) {
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
@@ -9196,8 +9196,14 @@
}
public void addCpuTimeLocked(int utime, int stime) {
- mUserTime += utime;
- mSystemTime += stime;
+ addCpuTimeLocked(utime, stime, mBsi.mOnBatteryTimeBase.isRunning());
+ }
+
+ public void addCpuTimeLocked(int utime, int stime, boolean isRunning) {
+ if (isRunning) {
+ mUserTime += utime;
+ mSystemTime += stime;
+ }
}
public void addForegroundTimeLocked(long ttime) {
@@ -11761,13 +11767,24 @@
}
}
+ public boolean isOnBatteryLocked() {
+ return mOnBatteryTimeBase.isRunning();
+ }
+
+ public boolean isOnBatteryScreenOffLocked() {
+ return mOnBatteryScreenOffTimeBase.isRunning();
+ }
+
/**
* Read and distribute CPU usage across apps. If their are partial wakelocks being held
* and we are on battery with screen off, we give more of the cpu time to those apps holding
* wakelocks. If the screen is on, we just assign the actual cpu time an app used.
+ * It's possible this will be invoked after the internal battery/screen states are updated, so
+ * passing the appropriate battery/screen states to try attribute the cpu times to correct
+ * buckets.
*/
@GuardedBy("this")
- public void updateCpuTimeLocked() {
+ public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff) {
if (mPowerProfile == null) {
return;
}
@@ -11784,7 +11801,7 @@
// usually holding the wakelock on behalf of an app.
// And Only distribute cpu power to wakelocks if the screen is off and we're on battery.
ArrayList<StopwatchTimer> partialTimersToConsider = null;
- if (mOnBatteryScreenOffTimeBase.isRunning()) {
+ if (onBatteryScreenOff) {
partialTimersToConsider = new ArrayList<>();
for (int i = mPartialTimers.size() - 1; i >= 0; --i) {
final StopwatchTimer timer = mPartialTimers.get(i);
@@ -11802,7 +11819,7 @@
// When the battery is not on, we don't attribute the cpu times to any timers but we still
// need to take the snapshots.
- if (!mOnBatteryInternal) {
+ if (!onBattery) {
mKernelUidCpuTimeReader.readDelta(null);
mKernelUidCpuFreqTimeReader.readDelta(null);
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
@@ -11818,16 +11835,16 @@
mUserInfoProvider.refreshUserIds();
final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()
? null : new SparseLongArray();
- readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids);
+ readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery);
// updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
// freqs, so no need to approximate these values.
if (updatedUids != null) {
- updateClusterSpeedTimes(updatedUids);
+ updateClusterSpeedTimes(updatedUids, onBattery);
}
- readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
+ readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff);
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
- readKernelUidCpuActiveTimesLocked();
- readKernelUidCpuClusterTimesLocked();
+ readKernelUidCpuActiveTimesLocked(onBattery);
+ readKernelUidCpuClusterTimesLocked(onBattery);
}
}
@@ -11867,7 +11884,7 @@
* @param updatedUids The uids for which times spent at different frequencies are calculated.
*/
@VisibleForTesting
- public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids) {
+ public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery) {
long totalCpuClustersTimeMs = 0;
// Read the time spent for each cluster at various cpu frequencies.
final long[][] clusterSpeedTimesMs = new long[mKernelCpuSpeedReaders.length][];
@@ -11909,7 +11926,7 @@
}
cpuSpeeds[speed].addCountLocked(appCpuTimeUs
* clusterSpeedTimesMs[cluster][speed]
- / totalCpuClustersTimeMs);
+ / totalCpuClustersTimeMs, onBattery);
}
}
}
@@ -11926,7 +11943,7 @@
*/
@VisibleForTesting
public void readKernelUidCpuTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
- @Nullable SparseLongArray updatedUids) {
+ @Nullable SparseLongArray updatedUids, boolean onBattery) {
mTempTotalCpuUserTimeUs = mTempTotalCpuSystemTimeUs = 0;
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
final long startTimeMs = mClocks.uptimeMillis();
@@ -11977,8 +11994,8 @@
Slog.d(TAG, sb.toString());
}
- u.mUserCpuTime.addCountLocked(userTimeUs);
- u.mSystemCpuTime.addCountLocked(systemTimeUs);
+ u.mUserCpuTime.addCountLocked(userTimeUs, onBattery);
+ u.mSystemCpuTime.addCountLocked(systemTimeUs, onBattery);
if (updatedUids != null) {
updatedUids.put(u.getUid(), userTimeUs + systemTimeUs);
}
@@ -12010,15 +12027,15 @@
Slog.d(TAG, sb.toString());
}
- timer.mUid.mUserCpuTime.addCountLocked(userTimeUs);
- timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
+ timer.mUid.mUserCpuTime.addCountLocked(userTimeUs, onBattery);
+ timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs, onBattery);
if (updatedUids != null) {
final int uid = timer.mUid.getUid();
updatedUids.put(uid, updatedUids.get(uid, 0) + userTimeUs + systemTimeUs);
}
final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
- proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
+ proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000, onBattery);
mTempTotalCpuUserTimeUs -= userTimeUs;
mTempTotalCpuSystemTimeUs -= systemTimeUs;
@@ -12033,7 +12050,8 @@
* @param partialTimers The wakelock holders among which the cpu freq times will be distributed.
*/
@VisibleForTesting
- public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers) {
+ public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
+ boolean onBattery, boolean onBatteryScreenOff) {
final boolean perClusterTimesAvailable =
mKernelUidCpuFreqTimeReader.perClusterTimesAvailable();
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
@@ -12056,13 +12074,13 @@
if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
- u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+ u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs, onBattery);
if (u.mScreenOffCpuFreqTimeMs == null ||
u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
mOnBatteryScreenOffTimeBase);
}
- u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+ u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs, onBatteryScreenOff);
if (perClusterTimesAvailable) {
if (u.mCpuClusterSpeedTimesUs == null ||
@@ -12098,7 +12116,7 @@
} else {
appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000;
}
- cpuTimesUs[speed].addCountLocked(appAllocationUs);
+ cpuTimesUs[speed].addCountLocked(appAllocationUs, onBattery);
freqIndex++;
}
}
@@ -12132,7 +12150,7 @@
}
final long allocationUs =
mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i);
- cpuTimeUs[speed].addCountLocked(allocationUs);
+ cpuTimeUs[speed].addCountLocked(allocationUs, onBattery);
mWakeLockAllocationsUs[cluster][speed] -= allocationUs;
}
}
@@ -12145,7 +12163,7 @@
* counters.
*/
@VisibleForTesting
- public void readKernelUidCpuActiveTimesLocked() {
+ public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesUs) -> {
uid = mapUid(uid);
@@ -12160,7 +12178,7 @@
return;
}
final Uid u = getUidStatsLocked(uid);
- u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs);
+ u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs, onBattery);
});
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12174,7 +12192,7 @@
* counters.
*/
@VisibleForTesting
- public void readKernelUidCpuClusterTimesLocked() {
+ public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesUs) -> {
uid = mapUid(uid);
@@ -12189,7 +12207,7 @@
return;
}
final Uid u = getUidStatsLocked(uid);
- u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs);
+ u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs, onBattery);
});
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12399,9 +12417,7 @@
reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null,
status, plugType, level, temp);
- final boolean onBattery =
- plugType == BATTERY_PLUGGED_NONE &&
- status != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ final boolean onBattery = isOnBattery(plugType, status);
final long uptime = mClocks.uptimeMillis();
final long elapsedRealtime = mClocks.elapsedRealtime();
if (!mHaveBatteryLevel) {
@@ -12591,6 +12607,10 @@
mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
}
+ public static boolean isOnBattery(int plugType, int status) {
+ return plugType == BATTERY_PLUGGED_NONE && status != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ }
+
// Inform StatsLog of setBatteryState changes.
// If this is the first reporting, pass in recentPast == null.
private void reportChangesToStatsLog(HistoryItem recentPast,
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
new file mode 100644
index 0000000..e37452d
--- /dev/null
+++ b/core/jni/OWNERS
@@ -0,0 +1,7 @@
+# Camera
+per-file *Camera*,*camera* = cychen@google.com
+per-file *Camera*,*camera* = epeev@google.com
+per-file *Camera*,*camera* = etalvala@google.com
+per-file *Camera*,*camera* = shuzhenwang@google.com
+per-file *Camera*,*camera* = yinchiayeh@google.com
+per-file *Camera*,*camera* = zhijunhe@google.com
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 2c05d0b..482d028 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -1008,23 +1008,6 @@
return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr);
}
- static jboolean equalsForTextMeasurement(jlong lPaint, jlong rPaint) {
- if (lPaint == rPaint) {
- return true;
- }
- Paint* leftPaint = reinterpret_cast<Paint*>(lPaint);
- Paint* rightPaint = reinterpret_cast<Paint*>(rPaint);
-
- const Typeface* leftTypeface = Typeface::resolveDefault(leftPaint->getAndroidTypeface());
- const Typeface* rightTypeface = Typeface::resolveDefault(rightPaint->getAndroidTypeface());
- minikin::MinikinPaint leftMinikinPaint
- = MinikinUtils::prepareMinikinPaint(leftPaint, leftTypeface);
- minikin::MinikinPaint rightMinikinPaint
- = MinikinUtils::prepareMinikinPaint(rightPaint, rightTypeface);
-
- return leftMinikinPaint == rightMinikinPaint;
- }
-
}; // namespace PaintGlue
static const JNINativeMethod methods[] = {
@@ -1124,8 +1107,7 @@
{"nGetStrikeThruPosition","(J)F", (void*) PaintGlue::getStrikeThruPosition},
{"nGetStrikeThruThickness","(J)F", (void*) PaintGlue::getStrikeThruThickness},
{"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
- {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer},
- {"nEqualsForTextMeasurement", "(JJ)Z", (void*)PaintGlue::equalsForTextMeasurement},
+ {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
};
int register_android_graphics_Paint(JNIEnv* env) {
diff --git a/core/proto/android/os/cpufreq.proto b/core/proto/android/os/cpufreq.proto
index 8481ffc..46f4901 100644
--- a/core/proto/android/os/cpufreq.proto
+++ b/core/proto/android/os/cpufreq.proto
@@ -16,32 +16,30 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "CpuFreqProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
// cpu frequency time from /sys/devices/system/cpu/cpufreq/all_time_in_state
-message CpuFreq {
+message CpuFreqProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 jiffy_hz = 1; // obtain by system config.
- repeated CpuFreqStats cpu_freqs = 2;
-}
-
-// frequency time pre cpu, unit in jiffy, TODO: obtain jiffies.
-message CpuFreqStats {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional string cpu_name = 1;
-
- message TimeInState {
+ // frequency time pre cpu, unit in jiffy.
+ message Stats {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 state_khz = 1; // cpu frequency
- optional int64 time_jiffy = 2; // number of jiffies
+ optional string cpu_name = 1;
+
+ message TimeInState {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 state_khz = 1; // cpu frequency
+ optional int64 time_jiffy = 2; // number of jiffies
+ }
+ repeated TimeInState times = 2;
}
- repeated TimeInState times = 2;
+ repeated Stats cpu_freqs = 2;
}
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
index ca43602..ce69fc9 100644
--- a/core/proto/android/os/cpuinfo.proto
+++ b/core/proto/android/os/cpuinfo.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "CpuInfoProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -28,7 +27,7 @@
*
* Next Tag: 6
*/
-message CpuInfo {
+message CpuInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
message TaskStats {
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 698f394..c0950bfc 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -122,32 +122,32 @@
];
// Linux services
- optional Procrank procrank = 2000 [
+ optional ProcrankProto procrank = 2000 [
(section).type = SECTION_NONE, // disable procrank until figure out permission
(section).args = "/system/xbin/procrank"
];
- optional PageTypeInfo page_type_info = 2001 [
+ optional PageTypeInfoProto page_type_info = 2001 [
(section).type = SECTION_FILE,
(section).args = "/proc/pagetypeinfo"
];
- optional KernelWakeSources kernel_wake_sources = 2002 [
+ optional KernelWakeSourcesProto kernel_wake_sources = 2002 [
(section).type = SECTION_FILE,
(section).args = "/d/wakeup_sources"
];
- optional CpuInfo cpu_info = 2003 [
+ optional CpuInfoProto cpu_info = 2003 [
(section).type = SECTION_COMMAND,
(section).args = "top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"
];
- optional CpuFreq cpu_freq = 2004 [
+ optional CpuFreqProto cpu_freq = 2004 [
(section).type = SECTION_FILE,
(section).args = "/sys/devices/system/cpu/cpufreq/all_time_in_state"
];
- optional PsDumpProto processes_and_threads = 2005 [
+ optional PsProto processes_and_threads = 2005 [
(section).type = SECTION_COMMAND,
(section).args = "ps -A -T -Z -O pri,nice,rtprio,sched,pcy,time"
];
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index c296dab..5021a06 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -16,41 +16,40 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "WakeupSourcesProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
-message KernelWakeSources {
+message KernelWakeSourcesProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Kernel records of what caused the application processor to wake up
- repeated WakeupSourceProto wakeup_sources = 1;
-}
+ message WakeupSource {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
-// Next Tag: 11
-message WakeupSourceProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // Name of the event which triggers application processor
+ optional string name = 1;
- // Name of the event which triggers application processor
- optional string name = 1;
+ optional int32 active_count = 2;
- optional int32 active_count = 2;
+ optional int32 event_count = 3;
- optional int32 event_count = 3;
+ optional int32 wakeup_count = 4;
- optional int32 wakeup_count = 4;
+ optional int32 expire_count = 5;
- optional int32 expire_count = 5;
+ optional int64 active_since = 6;
- optional int64 active_since = 6;
+ optional int64 total_time = 7;
- optional int64 total_time = 7;
+ optional int64 max_time = 8;
- optional int64 max_time = 8;
+ optional int64 last_change = 9;
- optional int64 last_change = 9;
+ optional int64 prevent_suspend_time = 10;
- optional int64 prevent_suspend_time = 10;
+ // Next Tag: 11
+ }
+ repeated WakeupSource wakeup_sources = 1;
}
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index b8f618b..f5d77d6 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "PageTypeInfoProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -37,49 +36,47 @@
*
* Next tag: 5
*/
-message PageTypeInfo {
+message PageTypeInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 page_block_order = 1;
optional int32 pages_per_block = 2;
- repeated MigrateTypeProto migrate_types = 3;
+ // Next tag: 5
+ message MigrateType {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- repeated BlockProto blocks = 4;
-}
+ optional int32 node = 1;
-// Next tag: 5
-message MigrateTypeProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional string zone = 2;
- optional int32 node = 1;
+ optional string type = 3;
- optional string zone = 2;
+ // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
+ repeated int32 free_pages_count = 4;
+ }
+ repeated MigrateType migrate_types = 3;
- optional string type = 3;
+ // Next tag: 9
+ message Block {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
- repeated int32 free_pages_count = 4;
-}
+ optional int32 node = 1;
-// Next tag: 9
-message BlockProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional string zone = 2;
- optional int32 node = 1;
+ optional int32 unmovable = 3;
- optional string zone = 2;
+ optional int32 reclaimable = 4;
- optional int32 unmovable = 3;
+ optional int32 movable = 5;
- optional int32 reclaimable = 4;
+ optional int32 cma = 6;
- optional int32 movable = 5;
+ optional int32 reserve = 7;
- optional int32 cma = 6;
-
- optional int32 reserve = 7;
-
- optional int32 isolate = 8;
+ optional int32 isolate = 8;
+ }
+ repeated Block blocks = 4;
}
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index 204a5af..ff7515e 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -16,78 +16,73 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "ProcrankProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
//Memory usage of running processes
-message Procrank {
+message ProcrankProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Currently running process
- repeated ProcessProto processes = 1;
+ // Next Tag: 11
+ message Process {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // ID of the process
+ optional int32 pid = 1;
+
+ // virtual set size, unit KB
+ optional int64 vss = 2;
+
+ // resident set size, unit KB
+ optional int64 rss = 3;
+
+ // proportional set size, unit KB
+ optional int64 pss = 4;
+
+ // unique set size, unit KB
+ optional int64 uss = 5;
+
+ // swap size, unit KB
+ optional int64 swap = 6;
+
+ // proportional swap size, unit KB
+ optional int64 pswap = 7;
+
+ // unique swap size, unit KB
+ optional int64 uswap = 8;
+
+ // zswap size, unit KB
+ optional int64 zswap = 9;
+
+ // process command
+ optional string cmdline = 10;
+ }
+ repeated Process processes = 1;
// Summary
- optional SummaryProto summary = 2;
-}
+ // Next Tag: 3
+ message Summary {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
-// Next Tag: 11
-message ProcessProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional Process total = 1;
- // ID of the process
- optional int32 pid = 1;
+ // TODO: sync on how to use these values
+ message Zram {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // virtual set size, unit KB
- optional int64 vss = 2;
+ optional string raw_text = 1;
+ }
+ optional Zram zram = 2;
- // resident set size, unit KB
- optional int64 rss = 3;
+ message Ram {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // proportional set size, unit KB
- optional int64 pss = 4;
-
- // unique set size, unit KB
- optional int64 uss = 5;
-
- // swap size, unit KB
- optional int64 swap = 6;
-
- // proportional swap size, unit KB
- optional int64 pswap = 7;
-
- // unique swap size, unit KB
- optional int64 uswap = 8;
-
- // zswap size, unit KB
- optional int64 zswap = 9;
-
- // process command
- optional string cmdline = 10;
-}
-
-// Next Tag: 3
-message SummaryProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional ProcessProto total = 1;
-
- optional ZramProto zram = 2;
-
- optional RamProto ram = 3;
-}
-
-// TODO: sync on how to use these values
-message ZramProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional string raw_text = 1;
-}
-
-message RamProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional string raw_text = 1;
+ optional string raw_text = 1;
+ }
+ optional Ram ram = 3;
+ }
+ optional Summary summary = 2;
}
diff --git a/core/proto/android/os/ps.proto b/core/proto/android/os/ps.proto
index 9cce727..0ab92d7 100644
--- a/core/proto/android/os/ps.proto
+++ b/core/proto/android/os/ps.proto
@@ -22,7 +22,7 @@
import "frameworks/base/libs/incident/proto/android/privacy.proto";
-message PsDumpProto {
+message PsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
message Process {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6f3c25f..3a527b5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -174,6 +174,10 @@
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
diff --git a/core/res/res/drawable/ic_settings_24dp.xml b/core/res/res/drawable/ic_settings_24dp.xml
index fc75f04..c70b122 100644
--- a/core/res/res/drawable/ic_settings_24dp.xml
+++ b/core/res/res/drawable/ic_settings_24dp.xml
@@ -16,9 +16,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
- android:pathData="M38.86 25.95c.08,-.64.14,-1.29.14,-1.95s-.06,-1.31,-.14,-1.95l4.23,-3.31c.38,-.3.49,-.84.24,-1.28l-4,-6.93c-.25,-.43,-.77,-.61,-1.22,-.43l-4.98 2.01c-1.03,-.79,-2.16,-1.46,-3.38,-1.97L29 4.84c-.09,-.47,-.5,-.84,-1,-.84h-8c-.5 0,-.91.37,-.99.84l-.75 5.3c-1.22.51,-2.35 1.17,-3.38 1.97L9.9 10.1c-.45,-.17,-.97 0,-1.22.43l-4 6.93c-.25.43,-.14.97.24 1.28l4.22 3.31C9.06 22.69 9 23.34 9 24s.06 1.31.14 1.95l-4.22 3.31c-.38.3,-.49.84,-.24 1.28l4 6.93c.25.43.77.61 1.22.43l4.98,-2.01c1.03.79 2.16 1.46 3.38 1.97l.75 5.3c.08.47.49.84.99.84h8c.5 0 .91,-.37.99,-.84l.75,-5.3c1.22,-.51 2.35,-1.17 3.38,-1.97l4.98 2.01c.45.17.97 0 1.22,-.43l4,-6.93c.25,-.43.14,-.97,-.24,-1.28l-4.22,-3.31zM24 31c-3.87 0,-7,-3.13,-7,-7s3.13,-7 7,-7 7 3.13 7 7,-3.13 7,-7 7z"/>
+ android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+ android:fillColor="#FF000000" />
</vector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 005d07d..d26567e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7918,6 +7918,10 @@
android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
-->
<attr name="maxLongVersionCode" format="string" />
+ <!-- The resource id of view that contains the URL bar of the HTML page being loaded.
+ Typically used when compatibility mode is used in a browser.
+ -->
+ <attr name="urlBarResourceId" format="string" />
</declare-styleable>
<!-- =============================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cf7925b..1f4425f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2913,8 +2913,8 @@
<item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">1.777778</item>
<!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
- <integer name="config_defaultPictureInPictureGravity">0x55</integer>
+ Currently, this maps to Gravity.TOP | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x35</integer>
<!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
ratio smaller than this is considered too tall and thin to be usable. Currently, this
@@ -3316,4 +3316,5 @@
<string-array name="config_wearActivityModeRadios">
<item>"wifi"</item>
</string-array>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 93f22f25..82fefef 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,6 +2869,7 @@
<public name="outlineSpotShadowColor" />
<public name="outlineAmbientShadowColor" />
<public name="maxLongVersionCode" />
+ <public name="urlBarResourceId" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0efb6f9..59c742e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -547,7 +547,7 @@
<string name="global_action_voice_assist">Voice Assist</string>
<!-- label for item that locks the phone and enforces that it can't be unlocked without strong authentication. [CHAR LIMIT=15] -->
- <string name="global_action_lockdown">Enter lockdown</string>
+ <string name="global_action_lockdown">Lockdown</string>
<!-- Text to use when the number in a notification info is too large
(greater than status_bar_notification_info_maxnum, defined in
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5a9dc7f..b69ded8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3262,4 +3262,5 @@
<java-symbol type="string" name="zen_upgrade_notification_title" />
<java-symbol type="string" name="zen_upgrade_notification_content" />
+
</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index dc8ed9e..85cf9b6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -495,6 +495,7 @@
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
+ Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P
Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 32053e3..cb049b7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -114,7 +114,7 @@
when(mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked();
+ mBatteryStatsImpl.updateCpuTimeLocked(false, false);
// VERIFY
assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
@@ -134,7 +134,7 @@
mBatteryStatsImpl.setOnBatteryInternal(true);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked();
+ mBatteryStatsImpl.updateCpuTimeLocked(true, false);
// VERIFY
verify(mUserInfoProvider).refreshUserIds();
@@ -213,7 +213,7 @@
}
// RUN
- mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids);
+ mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true);
// VERIFY
int totalClustersTimeMs = 0;
@@ -261,7 +261,7 @@
// RUN
final SparseLongArray updatedUids = new SparseLongArray();
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -294,7 +294,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -333,7 +333,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -368,7 +368,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -423,7 +423,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -470,7 +470,7 @@
// RUN
final SparseLongArray updatedUids = new SparseLongArray();
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids, true);
// VERIFY
long totalUserTimeUs = 0;
@@ -549,7 +549,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -582,7 +582,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -633,7 +633,7 @@
when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -676,7 +676,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -743,7 +743,7 @@
when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false);
// VERIFY
final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][];
@@ -832,7 +832,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -865,7 +865,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -909,7 +909,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -949,7 +949,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1006,7 +1006,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1047,7 +1047,7 @@
any(KernelUidCpuActiveTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1073,7 +1073,7 @@
any(KernelUidCpuActiveTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1112,7 +1112,7 @@
any(KernelUidCpuClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1142,7 +1142,7 @@
any(KernelUidCpuClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 82ac9da..01ddc15 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -161,9 +161,7 @@
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
elapsedTimeUs, STATS_SINCE_CHARGED);
- expectedRunTimeMs = stateRuntimeMap.get(
- ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE)
- + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
@@ -173,7 +171,8 @@
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND,
elapsedTimeUs, STATS_SINCE_CHARGED);
- expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND,
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 7b239f0..cb05253 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -171,6 +171,20 @@
return null;
}
+ @Override
+ public Future<?> scheduleCpuSyncDueToScreenStateChange(
+ boolean onBattery, boolean onBatteryScreenOff) {
+ return null;
+ }
+
+ @Override
+ public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
+ return null;
+ }
+
+ @Override
+ public void cancelCpuSyncDueToWakelockChange() {
+ }
}
}
diff --git a/core/tests/featureflagtests/OWNERS b/core/tests/featureflagtests/OWNERS
new file mode 100644
index 0000000..1a8fd2b
--- /dev/null
+++ b/core/tests/featureflagtests/OWNERS
@@ -0,0 +1,2 @@
+sbasi@google.com
+zhfan@google.com
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
index 994131a..9b9e811 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
@@ -29,13 +29,10 @@
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shard libraries we link against.
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_LDLIBS := -llog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 99cf587..fe32454 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtest32 native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
index 6c2679b..600a5d1 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
@@ -30,14 +30,10 @@
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shared libraries we link against.
-LOCAL_SHARED_LIBRARIES := \
- libutils liblog
+LOCAL_LDLIBS := -llog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index 0b6d750..ad9e746 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtest64 native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
index d668f29..8e9ac6b 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
@@ -29,14 +29,10 @@
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shard libraries we link against.
LOCAL_LDLIBS = -llog
-LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 3947e21..5c5088f 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtestdual native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 07df045..eacb727 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -22,7 +22,7 @@
import android.annotation.Size;
import android.graphics.Canvas.VertexMode;
import android.text.GraphicsOperations;
-import android.text.PrecomputedText;
+import android.text.MeasuredText;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
@@ -487,8 +487,8 @@
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
long measuredTextPtr = 0;
int measuredTextOffset = 0;
- if (text instanceof PrecomputedText) {
- PrecomputedText mt = (PrecomputedText) text;
+ if (text instanceof MeasuredText) {
+ MeasuredText mt = (MeasuredText) text;
int paraIndex = mt.findParaIndex(start);
if (end <= mt.getParagraphEnd(paraIndex)) {
// Only suppor the same paragraph.
@@ -647,7 +647,7 @@
private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
- long nativePrecomputedText, int measuredTextOffset);
+ long nativeMeasuredText, int measuredTextOffset);
private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 42dac38..ed147e9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2835,16 +2835,6 @@
return result;
}
- /**
- * Returns true of the passed {@link Paint} will have the same effect on text measurement
- *
- * @param other A {@link Paint} object.
- * @return true if the other {@link Paint} has the same effect on text measurement.
- */
- public boolean equalsForTextMeasurement(@NonNull Paint other) {
- return nEqualsForTextMeasurement(mNativePaint, other.mNativePaint);
- }
-
// regular JNI
private static native long nGetNativeFinalizer();
private static native long nInit();
@@ -3012,6 +3002,4 @@
private static native float nGetStrikeThruThickness(long paintPtr);
@CriticalNative
private static native void nSetTextSize(long paintPtr, float textSize);
- @CriticalNative
- private static native boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr);
}
diff --git a/media/OWNERS b/media/OWNERS
new file mode 100644
index 0000000..8f405e9
--- /dev/null
+++ b/media/OWNERS
@@ -0,0 +1,4 @@
+elaurent@google.com
+etalvala@google.com
+lajos@google.com
+marcone@google.com
diff --git a/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
new file mode 100644
index 0000000..e14c99b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5s5,2.2 5,5h2c0,-3.93 -3.07,-7 -7,-7S7,5.07 7,9c0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 2.21,0 4,-1.79 4,-4h-2c0,1.1 -0.9,2 -2,2zM7.64,2.64L6.22,1.22C4.23,3.21 3,5.96 3,9s1.23,5.79 3.22,7.78l1.41,-1.41C6.01,13.74 5,11.49 5,9s1.01,-4.74 2.64,-6.36zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e6f4ec6..c78f454 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -177,6 +177,11 @@
<!-- Bluetooth settings. Similar to bluetooth_profile_a2dp_high_quality, but used when the device supports high quality audio but we don't know which codec that will be used. -->
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec">HD audio</string>
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. -->
+ <string name="bluetooth_profile_hearing_aid">Hearing Aid</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
+ <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aid</string>
+
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference when headset is connected. -->
@@ -214,6 +219,8 @@
for the HID checkbox preference that describes how checking it
will set the HID profile as preferred. -->
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. -->
+ <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aid</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 1f67dfb..9947dec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,6 +1,7 @@
package com.android.settingslib;
import android.annotation.ColorInt;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -17,10 +18,13 @@
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.print.PrintManager;
import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.wrapper.LocationManagerWrapper;
@@ -30,6 +34,9 @@
private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
private static final String NEW_MODE_KEY = "NEW_MODE";
+ @VisibleForTesting
+ static final String STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY =
+ "ro.storage_manager.show_opt_in";
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
@@ -37,11 +44,11 @@
private static String sSharedSystemSharedLibPackageName;
static final int[] WIFI_PIE = {
- com.android.internal.R.drawable.ic_wifi_signal_0,
- com.android.internal.R.drawable.ic_wifi_signal_1,
- com.android.internal.R.drawable.ic_wifi_signal_2,
- com.android.internal.R.drawable.ic_wifi_signal_3,
- com.android.internal.R.drawable.ic_wifi_signal_4
+ com.android.internal.R.drawable.ic_wifi_signal_0,
+ com.android.internal.R.drawable.ic_wifi_signal_1,
+ com.android.internal.R.drawable.ic_wifi_signal_2,
+ com.android.internal.R.drawable.ic_wifi_signal_3,
+ com.android.internal.R.drawable.ic_wifi_signal_4
};
public static void updateLocationEnabled(Context context, boolean enabled, int userId,
@@ -262,7 +269,7 @@
*/
public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
if (sSystemSignature == null) {
- sSystemSignature = new Signature[]{ getSystemSignature(pm) };
+ sSystemSignature = new Signature[]{getSystemSignature(pm)};
}
if (sPermissionControllerPackageName == null) {
sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
@@ -274,7 +281,7 @@
sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
}
return (sSystemSignature[0] != null
- && sSystemSignature[0].equals(getFirstSignature(pkg)))
+ && sSystemSignature[0].equals(getFirstSignature(pkg)))
|| pkg.packageName.equals(sPermissionControllerPackageName)
|| pkg.packageName.equals(sServicesSystemSharedLibPackageName)
|| pkg.packageName.equals(sSharedSystemSharedLibPackageName)
@@ -312,7 +319,6 @@
* Returns the Wifi icon resource for a given RSSI level.
*
* @param level The number of bars to show (0-4)
- *
* @throws IllegalArgumentException if an invalid RSSI level is given.
*/
public static int getWifiIconResource(int level) {
@@ -342,4 +348,19 @@
return !context.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
+
+ /** Returns if the automatic storage management feature is turned on or not. **/
+ public static boolean isStorageManagerEnabled(Context context) {
+ boolean isDefaultOn;
+ try {
+ // Turn off by default if the opt-in was shown.
+ isDefaultOn = !SystemProperties.getBoolean(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, true);
+ } catch (Resources.NotFoundException e) {
+ isDefaultOn = false;
+ }
+ return Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
+ isDefaultOn ? 1 : 0)
+ != 0;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
new file mode 100644
index 0000000..8f9e4635
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -0,0 +1,235 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class HearingAidProfile implements LocalBluetoothProfile {
+ private static final String TAG = "HearingAidProfile";
+ private static boolean V = true;
+
+ private Context mContext;
+
+ private BluetoothHearingAid mService;
+ private boolean mIsProfileReady;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final String NAME = "HearingAid";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class HearingAidServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothHearingAid) proxy;
+ // We just bound to the service, so refresh the UI for any connected HearingAid devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "HearingAidProfile found new device: " + nextDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+ }
+ device.onProfileStateChanged(HearingAidProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+ mIsProfileReady=true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady=false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ HearingAidProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mContext = context;
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ mLocalAdapter.getProfileProxy(context, new HearingAidServiceListener(),
+ BluetoothProfile.HEARING_AID);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ // Downgrade priority as user is disconnecting the hearing aid.
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (mService == null) return;
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ public int getVolume() {
+ if (mService == null) {
+ return 0;
+ }
+ return mService.getVolume();
+ }
+
+ public void setVolume(int volume) {
+ if (mService == null) {
+ return;
+ }
+ mService.setVolume(volume);
+ }
+
+ public long getHiSyncId(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ }
+ return mService.getHiSyncId(device);
+ }
+
+ public int getDeviceSide(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.SIDE_LEFT;
+ }
+ return mService.getDeviceSide(device);
+ }
+
+ public int getDeviceMode(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.MODE_MONAURAL;
+ }
+ return mService.getDeviceMode(device);
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_hearing_aid;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_hearing_aid_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_hearing_aid_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_hearing_aid;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID,
+ mService);
+ mService = null;
+ }catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up Hearing Aid proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 991d922..34a099c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
@@ -91,6 +92,7 @@
private final PbapServerProfile mPbapProfile;
private final boolean mUsePbapPce;
private final boolean mUseMapClient;
+ private HearingAidProfile mHearingAidProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -143,10 +145,14 @@
//Create PBAP server profile
if(DEBUG) Log.d(TAG, "Adding local PBAP profile");
+
mPbapProfile = new PbapServerProfile(context);
addProfile(mPbapProfile, PbapServerProfile.NAME,
BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED);
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHearingAidProfile, HearingAidProfile.NAME,
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
@@ -254,6 +260,18 @@
"Warning: PBAP Client profile was previously added but the UUID is now missing.");
}
+ //Hearing Aid Client
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
+ if (mHearingAidProfile == null) {
+ if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHearingAidProfile, HearingAidProfile.NAME,
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ }
+ } else if (mHearingAidProfile != null) {
+ Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing.");
+ }
+
mEventManager.registerProfileIntentReceiver();
// There is no local SDP record for HID and Settings app doesn't control PBAP Server.
@@ -416,6 +434,10 @@
return mMapClientProfile;
}
+ public HearingAidProfile getHearingAidProfile() {
+ return mHearingAidProfile;
+ }
+
/**
* Fill in a list of LocalBluetoothProfile objects that are supported by
* the local device and the remote device.
@@ -515,6 +537,12 @@
removedProfiles.remove(mPbapClientProfile);
}
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
+ mHearingAidProfile != null) {
+ profiles.add(mHearingAidProfile);
+ removedProfiles.remove(mHearingAidProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index 1a54d6a..b98f27e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -76,6 +76,8 @@
protected Uri mForeverId;
private int mBucketIndex = -1;
+ @VisibleForTesting
+ protected NotificationManager mNotificationManager;
private AlarmManager mAlarmManager;
private int mUserId;
private boolean mAttached;
@@ -98,7 +100,7 @@
}
public Dialog createDialog() {
- NotificationManager noMan = (NotificationManager) mContext.
+ mNotificationManager = (NotificationManager) mContext.
getSystemService(Context.NOTIFICATION_SERVICE);
mForeverId = Condition.newId(mContext).appendPath("forever").build();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -131,7 +133,8 @@
Slog.d(TAG, "Invalid manual condition: " + tag.condition);
}
// always triggers priority-only dnd with chosen condition
- noMan.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ mNotificationManager.setZenMode(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
getRealConditionId(tag.condition), TAG);
}
});
@@ -465,7 +468,16 @@
mZenAlarmWarning.setVisibility(warningText == null ? View.GONE : View.VISIBLE);
}
- private String computeAlarmWarningText(Condition condition) {
+ @VisibleForTesting
+ protected String computeAlarmWarningText(Condition condition) {
+ boolean allowAlarms = (mNotificationManager.getNotificationPolicy().priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) != 0;
+
+ // don't show alarm warning if alarms are allowed to bypass dnd
+ if (allowAlarms) {
+ return null;
+ }
+
final long now = System.currentTimeMillis();
final long nextAlarm = getNextAlarm();
if (nextAlarm < now) {
@@ -483,14 +495,19 @@
if (warningRes == 0) {
return null;
}
+
+ return mContext.getResources().getString(warningRes, getTime(nextAlarm, now));
+ }
+
+ @VisibleForTesting
+ protected String getTime(long nextAlarm, long now) {
final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
- final String template = mContext.getResources().getString(templateRes, formattedTime);
- return mContext.getResources().getString(warningRes, template);
+ return mContext.getResources().getString(templateRes, formattedTime);
}
// used as the view tag on condition rows
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f699440..b380ac5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -17,6 +17,7 @@
package com.android.settingslib.wifi;
import android.annotation.IntDef;
+import android.annotation.MainThread;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
@@ -42,6 +43,8 @@
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -57,6 +60,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
+import com.android.settingslib.utils.ThreadUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -68,7 +72,14 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-
+/**
+ * Represents a selectable Wifi Network for use in various wifi selection menus backed by
+ * {@link WifiTracker}.
+ *
+ * <p>An AccessPoint, which would be more fittingly named "WifiNetwork", is an aggregation of
+ * {@link ScanResult ScanResults} along with pertinent metadata (e.g. current connection info,
+ * network scores) required to successfully render the network to the user.
+ */
public class AccessPoint implements Comparable<AccessPoint> {
static final String TAG = "SettingsLib.AccessPoint";
@@ -288,11 +299,6 @@
mId = sLastId.incrementAndGet();
}
- AccessPoint(Context context, AccessPoint other) {
- mContext = context;
- copyFrom(other);
- }
-
AccessPoint(Context context, Collection<ScanResult> results) {
mContext = context;
@@ -346,33 +352,6 @@
}
/**
- * Copy accesspoint information. NOTE: We do not copy tag information because that is never
- * set on the internal copy.
- */
- void copyFrom(AccessPoint that) {
- this.ssid = that.ssid;
- this.bssid = that.bssid;
- this.security = that.security;
- this.mKey = that.mKey;
- this.networkId = that.networkId;
- this.pskType = that.pskType;
- this.mConfig = that.mConfig; //TODO: Watch out, this object is mutated.
- this.mRssi = that.mRssi;
- this.mInfo = that.mInfo;
- this.mNetworkInfo = that.mNetworkInfo;
- this.mScanResults.clear();
- this.mScanResults.addAll(that.mScanResults);
- this.mScoredNetworkCache.clear();
- this.mScoredNetworkCache.putAll(that.mScoredNetworkCache);
- this.mId = that.mId;
- this.mSpeed = that.mSpeed;
- this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered;
- this.mIsCarrierAp = that.mIsCarrierAp;
- this.mCarrierApEapType = that.mCarrierApEapType;
- this.mCarrierName = that.mCarrierName;
- }
-
- /**
* Returns a negative integer, zero, or a positive integer if this AccessPoint is less than,
* equal to, or greater than the other AccessPoint.
*
@@ -467,7 +446,7 @@
}
builder.append(",metered=").append(isMetered());
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
builder.append(",rssi=").append(mRssi);
builder.append(",scan cache size=").append(mScanResults.size());
}
@@ -546,7 +525,7 @@
mSpeed = generateAverageSpeedForSsid();
boolean changed = oldSpeed != mSpeed;
- if(WifiTracker.sVerboseLogging && changed) {
+ if(isVerboseLoggingEnabled() && changed) {
Log.i(TAG, String.format("%s: Set speed to %d", ssid, mSpeed));
}
return changed;
@@ -577,7 +556,7 @@
}
}
int speed = count == 0 ? Speed.NONE : totalSpeed / count;
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, String.format("%s generated fallback speed is: %d", getSsidStr(), speed));
}
return roundToClosestSpeedEnum(speed);
@@ -913,7 +892,7 @@
}
}
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
summary.append(WifiUtils.buildLoggingSummary(this, config));
}
@@ -1070,12 +1049,12 @@
// Only update labels on visible rssi changes
updateSpeed();
if (mAccessPointListener != null) {
- mAccessPointListener.onLevelChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onLevelChanged(this));
}
}
if (mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this));
}
if (!scanResults.isEmpty()) {
@@ -1123,10 +1102,10 @@
mNetworkInfo = null;
}
if (updated && mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this));
if (oldLevel != getLevel() /* current level */) {
- mAccessPointListener.onLevelChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onLevelChanged(this));
}
}
@@ -1137,7 +1116,7 @@
mConfig = config;
networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
if (mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this));
}
}
@@ -1333,8 +1312,44 @@
return string;
}
+ /**
+ * Callbacks relaying changes to the AccessPoint representation.
+ *
+ * <p>All methods are invoked on the Main Thread.
+ */
public interface AccessPointListener {
- void onAccessPointChanged(AccessPoint accessPoint);
- void onLevelChanged(AccessPoint accessPoint);
+ /**
+ * Indicates a change to the externally visible state of the AccessPoint trigger by an
+ * update of ScanResults, saved configuration state, connection state, or score
+ * (labels/metered) state.
+ *
+ * <p>Clients should refresh their view of the AccessPoint to match the updated state when
+ * this is invoked. Overall this method is extraneous if clients are listening to
+ * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks.
+ *
+ * <p>Examples of changes include signal strength, connection state, speed label, and
+ * generally anything that would impact the summary string.
+ *
+ * @param accessPoint The accessPoint object the listener was registered on which has
+ * changed
+ */
+ @MainThread void onAccessPointChanged(AccessPoint accessPoint);
+
+ /**
+ * Indicates the "wifi pie signal level" has changed, retrieved via calls to
+ * {@link AccessPoint#getLevel()}.
+ *
+ * <p>This call is a subset of {@link #onAccessPointChanged(AccessPoint)} , hence is also
+ * extraneous if the client is already reacting to that or the
+ * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks.
+ *
+ * @param accessPoint The accessPoint object the listener was registered on whose level has
+ * changed
+ */
+ @MainThread void onLevelChanged(AccessPoint accessPoint);
+ }
+
+ private static boolean isVerboseLoggingEnabled() {
+ return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index fac585e..ae544dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -15,6 +15,7 @@
*/
package com.android.settingslib.wifi;
+import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -48,8 +49,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.widget.Toast;
import com.android.settingslib.R;
@@ -58,6 +57,7 @@
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.utils.ThreadUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -88,8 +88,17 @@
return Log.isLoggable(TAG, Log.DEBUG);
}
- /** verbose logging flag. this flag is set thru developer debugging options
- * and used so as to assist with in-the-field WiFi connectivity debugging */
+ private static boolean isVerboseLoggingEnabled() {
+ return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
+ }
+
+ /**
+ * Verbose logging flag set thru developer debugging options and used so as to assist with
+ * in-the-field WiFi connectivity debugging.
+ *
+ * <p>{@link #isVerboseLoggingEnabled()} should be read rather than referencing this value
+ * directly, to ensure adb TAG level verbose settings are respected.
+ */
public static boolean sVerboseLogging;
// TODO: Allow control of this?
@@ -104,7 +113,6 @@
private final NetworkRequest mNetworkRequest;
private final AtomicBoolean mConnected = new AtomicBoolean(false);
private final WifiListener mListener;
- @VisibleForTesting MainHandler mMainHandler;
@VisibleForTesting WorkHandler mWorkHandler;
private HandlerThread mWorkThread;
@@ -113,35 +121,17 @@
@GuardedBy("mLock")
private boolean mRegistered;
- /**
- * The externally visible access point list.
- *
- * Updated using main handler. Clone of this collection is returned from
- * {@link #getAccessPoints()}
- */
- private final List<AccessPoint> mAccessPoints = new ArrayList<>();
-
- /**
- * The internal list of access points, synchronized on itself.
- *
- * Never exposed outside this class.
- */
+ /** The list of AccessPoints, aggregated visible ScanResults with metadata. */
@GuardedBy("mLock")
private final List<AccessPoint> mInternalAccessPoints = new ArrayList<>();
/**
* Synchronization lock for managing concurrency between main and worker threads.
*
- * <p>This lock should be held for all background work.
- * TODO(b/37674366): Remove the worker thread so synchronization is no longer necessary.
+ * <p>This lock should be held for all modifications to {@link #mInternalAccessPoints}.
*/
private final Object mLock = new Object();
- //visible to both worker and main thread.
- @GuardedBy("mLock")
- private final AccessPointListenerAdapter mAccessPointListenerAdapter
- = new AccessPointListenerAdapter();
-
private final HashMap<String, Integer> mSeenBssids = new HashMap<>();
// TODO(sghuman): Change this to be keyed on AccessPoint.getKey
@@ -161,6 +151,12 @@
@VisibleForTesting
Scanner mScanner;
+ /**
+ * Tracks whether fresh scan results have been received since scanning start.
+ *
+ * <p>If this variable is false, we will not evict the scan result cache or invoke callbacks
+ * so that we do not update the UI with stale data / clear out existing UI elements prematurely.
+ */
@GuardedBy("mLock")
private boolean mStaleScanResults = true;
@@ -209,12 +205,11 @@
NetworkScoreManager networkScoreManager,
IntentFilter filter) {
mContext = context;
- mMainHandler = new MainHandler(Looper.getMainLooper());
mWifiManager = wifiManager;
mListener = new WifiListenerWrapper(wifiListener);
mConnectivityManager = connectivityManager;
- // check if verbose logging has been turned on or off
+ // check if verbose logging developer option has been turned on or off
sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
mFilter = filter;
@@ -226,6 +221,7 @@
mNetworkScoreManager = networkScoreManager;
+ // TODO(sghuman): Remove this and create less hacky solution for testing
final HandlerThread workThread = new HandlerThread(TAG
+ "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -238,6 +234,8 @@
* @param workThread substitute Handler thread, for testing purposes only
*/
@VisibleForTesting
+ // TODO(sghuman): Remove this method, this needs to happen in a factory method and be passed in
+ // during construction
void setWorkThread(HandlerThread workThread) {
mWorkThread = workThread;
mWorkHandler = new WorkHandler(workThread.getLooper());
@@ -270,32 +268,29 @@
mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
mInternalAccessPoints.clear();
updateAccessPointsLocked(newScanResults, configs);
-
- // Synchronously copy access points
- mMainHandler.removeMessages(MainHandler.MSG_ACCESS_POINT_CHANGED);
- mMainHandler.handleMessage(
- Message.obtain(mMainHandler, MainHandler.MSG_ACCESS_POINT_CHANGED));
- if (sVerboseLogging) {
- Log.i(TAG, "force update - external access point list:\n" + mAccessPoints);
- }
}
}
/**
* Temporarily stop scanning for wifi networks.
+ *
+ * <p>Sets {@link #mStaleScanResults} to true.
*/
- public void pauseScanning() {
+ private void pauseScanning() {
if (mScanner != null) {
mScanner.pause();
mScanner = null;
}
+ synchronized (mLock) {
+ mStaleScanResults = true;
+ }
}
/**
@@ -387,11 +382,9 @@
mRegistered = false;
}
unregisterScoreCache();
- pauseScanning();
+ pauseScanning(); // and set mStaleScanResults
mWorkHandler.removePendingMessages();
- mMainHandler.removePendingMessages();
- mStaleScanResults = true;
}
}
@@ -409,12 +402,19 @@
}
/**
- * Gets the current list of access points. Should be called from main thread, otherwise
- * expect inconsistencies
+ * Gets the current list of access points.
+ *
+ * <p>This method is can be called on an abitrary thread by clients, but is normally called on
+ * the UI Thread by the rendering App.
*/
- @MainThread
+ @AnyThread
public List<AccessPoint> getAccessPoints() {
- return new ArrayList<>(mAccessPoints);
+ // TODO(sghuman): Investigate how to eliminate or reduce the need for locking now that we
+ // have transitioned to a single worker thread model.
+
+ synchronized (mLock) {
+ return new ArrayList<>(mInternalAccessPoints);
+ }
}
public WifiManager getManager() {
@@ -447,6 +447,8 @@
}
private void handleResume() {
+ // TODO(sghuman): Investigate removing this and replacing it with a cache eviction call
+ // instead.
mScanResultCache.clear();
mSeenBssids.clear();
}
@@ -509,7 +511,7 @@
private void updateAccessPoints() {
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
@@ -524,11 +526,15 @@
* Update the internal list of access points.
*
* <p>Do not call directly (except for forceUpdate), use {@link #updateAccessPoints()} which
- * respects {@link #mStaleScanResults}.
+ * acquires the lock first.
*/
@GuardedBy("mLock")
private void updateAccessPointsLocked(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) {
+ // TODO(sghuman): Reduce the synchronization time by only holding the lock when
+ // modifying lists exposed to operations on the MainThread (getAccessPoints, stopTracking,
+ // startTracking, etc).
+
WifiConfiguration connectionConfig = null;
if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(
@@ -634,7 +640,7 @@
mInternalAccessPoints.clear();
mInternalAccessPoints.addAll(accessPoints);
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ conditionallyNotifyListeners();
}
@VisibleForTesting
@@ -650,7 +656,6 @@
}
}
final AccessPoint accessPoint = new AccessPoint(mContext, scanResults);
- accessPoint.setListener(mAccessPointListenerAdapter);
return accessPoint;
}
@@ -661,16 +666,17 @@
if (cache.get(i).matches(config)) {
AccessPoint ret = cache.remove(i);
ret.loadConfig(config);
+
return ret;
}
}
final AccessPoint accessPoint = new AccessPoint(mContext, config);
- accessPoint.setListener(mAccessPointListenerAdapter);
return accessPoint;
}
private void updateNetworkInfo(NetworkInfo networkInfo) {
- /* sticky broadcasts can call this when wifi is disabled */
+
+ /* Sticky broadcasts can call this when wifi is disabled */
if (!mWifiManager.isWifiEnabled()) {
clearAccessPointsAndConditionallyUpdate();
return;
@@ -681,6 +687,10 @@
if (DBG()) {
Log.d(TAG, "mLastNetworkInfo set: " + mLastNetworkInfo);
}
+
+ if(networkInfo.isConnected() != mConnected.getAndSet(networkInfo.isConnected())) {
+ mListener.onConnectedChanged();
+ }
}
WifiConfiguration connectionConfig = null;
@@ -711,18 +721,25 @@
}
}
- if (reorder) Collections.sort(mInternalAccessPoints);
- if (updated) mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ if (reorder) {
+ Collections.sort(mInternalAccessPoints);
+ }
+ if (updated) {
+ conditionallyNotifyListeners();
+ }
}
}
+ /**
+ * Clears the access point list and conditionally invokes
+ * {@link WifiListener#onAccessPointsChanged()} if required (i.e. the list was not already
+ * empty).
+ */
private void clearAccessPointsAndConditionallyUpdate() {
synchronized (mLock) {
if (!mInternalAccessPoints.isEmpty()) {
mInternalAccessPoints.clear();
- if (!mMainHandler.hasMessages(MainHandler.MSG_ACCESS_POINT_CHANGED)) {
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
- }
+ mListener.onAccessPointsChanged();
}
}
}
@@ -745,27 +762,26 @@
}
if (updated) {
Collections.sort(mInternalAccessPoints);
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ conditionallyNotifyListeners();
}
}
}
- private void updateWifiState(int state) {
- mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
- if (!mWifiManager.isWifiEnabled()) {
- clearAccessPointsAndConditionallyUpdate();
- }
- }
-
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // No work should be performed in this Receiver, instead all operations should be passed
+ // off to the WorkHandler to avoid concurrent modification exceptions.
+
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
- updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN));
+ mWorkHandler.obtainMessage(
+ WorkHandler.MSG_UPDATE_WIFI_STATE,
+ intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN),
+ 0).sendToTarget();
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
mWorkHandler
.obtainMessage(
@@ -778,12 +794,6 @@
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-
- if(mConnected.get() != info.isConnected()) {
- mConnected.set(info.isConnected());
- mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
- }
-
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
.sendToTarget();
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
@@ -808,68 +818,8 @@
}
@VisibleForTesting
- final class MainHandler extends Handler {
- @VisibleForTesting static final int MSG_CONNECTED_CHANGED = 0;
- @VisibleForTesting static final int MSG_WIFI_STATE_CHANGED = 1;
- @VisibleForTesting static final int MSG_ACCESS_POINT_CHANGED = 2;
- private static final int MSG_RESUME_SCANNING = 3;
- private static final int MSG_PAUSE_SCANNING = 4;
-
- public MainHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mListener == null) {
- return;
- }
- switch (msg.what) {
- case MSG_CONNECTED_CHANGED:
- mListener.onConnectedChanged();
- break;
- case MSG_WIFI_STATE_CHANGED:
- mListener.onWifiStateChanged(msg.arg1);
- break;
- case MSG_ACCESS_POINT_CHANGED:
- // Only notify listeners of changes if we have fresh scan results, otherwise the
- // UI will be updated with stale results. We want to copy the APs regardless,
- // for instances where forceUpdate was invoked by the caller.
- if (mStaleScanResults) {
- copyAndNotifyListeners(false /*notifyListeners*/);
- } else {
- copyAndNotifyListeners(true /*notifyListeners*/);
- mListener.onAccessPointsChanged();
- }
- break;
- case MSG_RESUME_SCANNING:
- if (mScanner != null) {
- mScanner.resume();
- }
- break;
- case MSG_PAUSE_SCANNING:
- if (mScanner != null) {
- mScanner.pause();
- }
- synchronized (mLock) {
- mStaleScanResults = true;
- }
- break;
- }
- }
-
- void removePendingMessages() {
- removeMessages(MSG_ACCESS_POINT_CHANGED);
- removeMessages(MSG_CONNECTED_CHANGED);
- removeMessages(MSG_WIFI_STATE_CHANGED);
- removeMessages(MSG_PAUSE_SCANNING);
- removeMessages(MSG_RESUME_SCANNING);
- }
- }
-
- @VisibleForTesting
final class WorkHandler extends Handler {
- private static final int MSG_UPDATE_ACCESS_POINTS = 0;
+ @VisibleForTesting static final int MSG_UPDATE_ACCESS_POINTS = 0;
private static final int MSG_UPDATE_NETWORK_INFO = 1;
private static final int MSG_RESUME = 2;
private static final int MSG_UPDATE_WIFI_STATE = 3;
@@ -882,6 +832,8 @@
@Override
public void handleMessage(Message msg) {
+ // TODO(sghuman): Clean up synchronization to only be used when modifying collections
+ // exposed to the MainThread (through onStart, onStop, forceUpdate).
synchronized (mLock) {
processMessage(msg);
}
@@ -911,6 +863,7 @@
mScanner.resume();
}
} else {
+ clearAccessPointsAndConditionallyUpdate();
mLastInfo = null;
mLastNetworkInfo = null;
if (mScanner != null) {
@@ -920,8 +873,7 @@
mStaleScanResults = true;
}
}
- mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
- .sendToTarget();
+ mListener.onWifiStateChanged(msg.arg1);
break;
}
}
@@ -1010,16 +962,26 @@
@Override
public void onWifiStateChanged(int state) {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG,
+ String.format("Invoking onWifiStateChanged callback with state %d", state));
+ }
mHandler.post(() -> mDelegatee.onWifiStateChanged(state));
}
@Override
public void onConnectedChanged() {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "Invoking onConnectedChanged callback");
+ }
mHandler.post(() -> mDelegatee.onConnectedChanged());
}
@Override
public void onAccessPointsChanged() {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "Invoking onAccessPointsChanged callback");
+ }
mHandler.post(() -> mDelegatee.onAccessPointsChanged());
}
}
@@ -1041,101 +1003,27 @@
void onWifiStateChanged(int state);
/**
- * Called when the connection state of wifi has changed and isConnected
- * should be called to get the updated state.
+ * Called when the connection state of wifi has changed and
+ * {@link WifiTracker#isConnected()} should be called to get the updated state.
*/
void onConnectedChanged();
/**
* Called to indicate the list of AccessPoints has been updated and
- * getAccessPoints should be called to get the latest information.
+ * {@link WifiTracker#getAccessPoints()} should be called to get the updated list.
*/
void onAccessPointsChanged();
}
/**
- * Helps capture notifications that were generated during AccessPoint modification. Used later
- * on by {@link #copyAndNotifyListeners(boolean)} to send notifications.
+ * Invokes {@link WifiListenerWrapper#onAccessPointsChanged()} if {@link #mStaleScanResults}
+ * is false.
*/
- private static class AccessPointListenerAdapter implements AccessPoint.AccessPointListener {
- static final int AP_CHANGED = 1;
- static final int LEVEL_CHANGED = 2;
-
- final SparseIntArray mPendingNotifications = new SparseIntArray();
-
- @Override
- public void onAccessPointChanged(AccessPoint accessPoint) {
- int type = mPendingNotifications.get(accessPoint.mId);
- mPendingNotifications.put(accessPoint.mId, type | AP_CHANGED);
+ private void conditionallyNotifyListeners() {
+ if (mStaleScanResults) {
+ return;
}
- @Override
- public void onLevelChanged(AccessPoint accessPoint) {
- int type = mPendingNotifications.get(accessPoint.mId);
- mPendingNotifications.put(accessPoint.mId, type | LEVEL_CHANGED);
- }
- }
-
- /**
- * Responsible for copying access points from {@link #mInternalAccessPoints} and notifying
- * accesspoint listeners.
- *
- * @param notifyListeners if true, accesspoint listeners are notified, otherwise notifications
- * dropped.
- */
- @MainThread
- private void copyAndNotifyListeners(boolean notifyListeners) {
- // Need to watch out for memory allocations on main thread.
- SparseArray<AccessPoint> oldAccessPoints = new SparseArray<>();
- SparseIntArray notificationMap = null;
- List<AccessPoint> updatedAccessPoints = new ArrayList<>();
-
- for (AccessPoint accessPoint : mAccessPoints) {
- oldAccessPoints.put(accessPoint.mId, accessPoint);
- }
-
- synchronized (mLock) {
- if (DBG()) {
- Log.d(TAG, "Starting to copy AP items on the MainHandler. Internal APs: "
- + mInternalAccessPoints);
- }
-
- if (notifyListeners) {
- notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
- }
-
- mAccessPointListenerAdapter.mPendingNotifications.clear();
-
- for (AccessPoint internalAccessPoint : mInternalAccessPoints) {
- AccessPoint accessPoint = oldAccessPoints.get(internalAccessPoint.mId);
- if (accessPoint == null) {
- accessPoint = new AccessPoint(mContext, internalAccessPoint);
- } else {
- accessPoint.copyFrom(internalAccessPoint);
- }
- updatedAccessPoints.add(accessPoint);
- }
- }
-
- mAccessPoints.clear();
- mAccessPoints.addAll(updatedAccessPoints);
-
- if (notificationMap != null && notificationMap.size() > 0) {
- for (AccessPoint accessPoint : updatedAccessPoints) {
- int notificationType = notificationMap.get(accessPoint.mId);
- AccessPoint.AccessPointListener listener = accessPoint.mAccessPointListener;
- if (notificationType == 0 || listener == null) {
- continue;
- }
-
- if ((notificationType & AccessPointListenerAdapter.AP_CHANGED) != 0) {
- listener.onAccessPointChanged(accessPoint);
- }
-
- if ((notificationType & AccessPointListenerAdapter.LEVEL_CHANGED) != 0) {
- listener.onLevelChanged(accessPoint);
- }
- }
- }
+ ThreadUtils.postOnMainThread(() -> mListener.onAccessPointsChanged());
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 1440311..54c02a2 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -113,38 +113,6 @@
}
@Test
- public void testCopyAccessPoint_dataShouldMatch() {
- WifiConfiguration configuration = createWifiConfiguration();
- configuration.meteredHint = true;
-
- NetworkInfo networkInfo =
- new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
- AccessPoint originalAccessPoint = new AccessPoint(mContext, configuration);
- WifiInfo wifiInfo = new WifiInfo();
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
- wifiInfo.setBSSID(configuration.BSSID);
- originalAccessPoint.update(configuration, wifiInfo, networkInfo);
- AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
-
- assertThat(originalAccessPoint.getSsid().toString()).isEqualTo(copy.getSsid().toString());
- assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
- assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
- assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
- assertThat(originalAccessPoint.isMetered()).isEqualTo(copy.isMetered());
- assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
- }
-
- @Test
- public void testThatCopyAccessPoint_scanCacheShouldMatch() {
- AccessPoint original = createAccessPointWithScanResultCache();
- assertThat(original.getRssi()).isEqualTo(4);
- AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
- assertThat(copy.getRssi()).isEqualTo(AccessPoint.UNREACHABLE_RSSI);
- copy.copyFrom(original);
- assertThat(original.getRssi()).isEqualTo(copy.getRssi());
- }
-
- @Test
public void testCompareTo_GivesActiveBeforeInactive() {
AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 6be4936..0c49bb6 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -356,19 +356,14 @@
private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
throws InterruptedException {
+ // TODO(sghuman): This should no longer be necessary in a single work handler model
+
CountDownLatch workerLatch = new CountDownLatch(1);
tracker.mWorkHandler.post(() -> {
workerLatch.countDown();
});
assertTrue("Latch timed out while waiting for WorkerHandler",
workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
-
- CountDownLatch mainLatch = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
- mainLatch.countDown();
- });
- assertTrue("Latch timed out while waiting for MainHandler",
- mainLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
}
private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
@@ -390,38 +385,6 @@
}
@Test
- public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
- ScanResult scanResult = new ScanResult();
- scanResult.level = 123;
- scanResult.BSSID = "bssid-" + 111;
- scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
- scanResult.capabilities = "";
-
- WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, true, true);
-
- AccessPoint result = tracker.getCachedOrCreate(
- Collections.singletonList(scanResult), new ArrayList<AccessPoint>());
- assertTrue(result.mAccessPointListener != null);
- }
-
- @Test
- public void testAccessPointListenerSetWhenLookingUpUsingWifiConfiguration() {
- WifiConfiguration configuration = new WifiConfiguration();
- configuration.SSID = "test123";
- configuration.BSSID="bssid";
- configuration.networkId = 123;
- configuration.allowedKeyManagement = new BitSet();
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
-
- WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, true, true);
-
- AccessPoint result = tracker.getCachedOrCreate(configuration, new ArrayList<AccessPoint>());
- assertTrue(result.mAccessPointListener != null);
- }
-
- @Test
public void startAndStopTrackingShouldRegisterAndUnregisterScoreCache()
throws InterruptedException {
WifiTracker tracker = createMockedWifiTracker();
@@ -534,7 +497,6 @@
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
}
- @FlakyTest
@Test
public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
@@ -634,9 +596,9 @@
public void scoresShouldBeRequestedForNewScanResultOnly() throws InterruptedException {
// Scores can be requested together or serially depending on how the scan results are
// processed.
- mRequestScoresLatch = new CountDownLatch(2);
+ mRequestScoresLatch = new CountDownLatch(1);
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
mRequestedKeys.clear();
String ssid = "ssid3";
@@ -770,7 +732,7 @@
CountDownLatch ready = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch lock = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
+ tracker.mWorkHandler.post(() -> {
try {
ready.countDown();
lock.await();
@@ -781,12 +743,7 @@
});
// Enqueue messages
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_ACCESS_POINT_CHANGED);
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_CONNECTED_CHANGED);
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED);
+ tracker.mWorkHandler.sendEmptyMessage(WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS);
try {
ready.await(); // Make sure we have entered the first message handler
@@ -800,12 +757,9 @@
lock.countDown();
assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_ACCESS_POINT_CHANGED)).isFalse();
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_CONNECTED_CHANGED)).isFalse();
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED)).isFalse();
+ assertThat(tracker.mWorkHandler.hasMessages(
+ WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS)).isFalse();
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
verifyNoMoreInteractions(mockWifiListener);
}
@@ -862,7 +816,7 @@
mAccessPointsChangedLatch = new CountDownLatch(1);
tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
- mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
assertThat(tracker.getAccessPoints()).isEmpty();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 12d3106..706d0c0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+
+import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.eq;
@@ -30,6 +33,7 @@
import android.content.Intent;
import android.content.res.Resources;
import android.location.LocationManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Secure;
@@ -136,7 +140,7 @@
}
@Test
- public void testStorageManagerDaysToRetainUsesResources() {
+ public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
eq(
@@ -149,6 +153,12 @@
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
+ @Test
+ public void testIsStorageManagerEnabled_UsesSystemProperties() {
+ SystemProperties.set(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, "false");
+ assertThat(Utils.isStorageManagerEnabled(mContext)).isTrue();
+ }
+
private static ArgumentMatcher<Intent> actionMatches(String expected) {
return intent -> TextUtils.equals(expected, intent.getAction());
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
index 9b5da4a..ccd2f53 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
@@ -17,15 +17,22 @@
package com.android.settingslib.notification;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
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 static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Fragment;
+import android.app.NotificationManager;
import android.content.Context;
+import android.content.res.Resources;
import android.net.Uri;
import android.service.notification.Condition;
import android.view.LayoutInflater;
@@ -46,7 +53,11 @@
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+ @Mock
private Fragment mFragment;
+ @Mock
+ private NotificationManager mNotificationManager;
private Context mShadowContext;
private LayoutInflater mLayoutInflater;
@@ -58,6 +69,7 @@
MockitoAnnotations.initMocks(this);
mShadowContext = RuntimeEnvironment.application;
when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getResources()).thenReturn(mResources);
when(mFragment.getContext()).thenReturn(mShadowContext);
mLayoutInflater = LayoutInflater.from(mShadowContext);
@@ -67,6 +79,10 @@
mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
.thenReturn("testSummary");
+ NotificationManager.Policy alarmsEnabledPolicy = new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0);
+ doReturn(alarmsEnabledPolicy).when(mNotificationManager).getNotificationPolicy();
+ mController.mNotificationManager = mNotificationManager;
mController.getContentView();
// these methods use static calls to ZenModeConfig which would normally fail in robotests,
@@ -141,4 +157,38 @@
assertFalse(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
+
+ @Test
+ public void testNoAlarmWarning() {
+ // setup alarm
+ long now = System.currentTimeMillis();
+ doReturn(now + 100000).when(mController).getNextAlarm();
+ doReturn("").when(mController).getTime(anyLong(), anyLong());
+
+ // allow alarms
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0));
+
+ // alarm warning should be null
+ assertNull(mController.computeAlarmWarningText(null));
+ }
+
+ @Test
+ public void testAlarmWarning() {
+ // setup alarm
+ long now = System.currentTimeMillis();
+ doReturn(now + 1000000).when(mController).getNextAlarm();
+ doReturn("").when(mController).getTime(anyLong(), anyLong());
+
+ // don't allow alarms to bypass dnd
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0, 0, 0, 0));
+
+ // return a string if mResources is asked to retrieve a string
+ when(mResources.getString(anyInt(), anyString())).thenReturn("");
+
+ // alarm warning should NOT be null
+ assertNotNull(mController.computeAlarmWarningText(null));
+ }
}
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 91957e1..ad422d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -76,11 +76,10 @@
*/
private static final ArraySet<String> sBroadcastOnRestore;
static {
- sBroadcastOnRestore = new ArraySet<String>(5);
+ sBroadcastOnRestore = new ArraySet<String>(4);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 85a579d..87ea382 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1591,6 +1591,7 @@
private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
String value, int callingUid) {
String restriction;
+ boolean checkAllUser = false;
switch (setting) {
case Settings.Secure.LOCATION_MODE:
// Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
@@ -1656,6 +1657,12 @@
restriction = UserManager.DISALLOW_AMBIENT_DISPLAY;
break;
+ case Global.LOCATION_GLOBAL_KILL_SWITCH:
+ if ("0".equals(value)) return false;
+ restriction = UserManager.DISALLOW_CONFIG_LOCATION;
+ checkAllUser = true;
+ break;
+
default:
if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
if ("0".equals(value)) return false;
@@ -1665,7 +1672,11 @@
return false;
}
- return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
+ if (checkAllUser) {
+ return mUserManager.hasUserRestrictionOnAnyUser(restriction);
+ } else {
+ return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
+ }
}
private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index af6dd77..7c97ca61 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -2,19 +2,23 @@
dsandler@google.com
+adamcohen@google.com
asc@google.com
ashaikh@google.com
beverlyt@google.com
cinek@google.com
cwren@google.com
+dupin@google.com
evanlaird@google.com
jmonk@google.com
jaggies@google.com
jjaggi@google.com
juliacr@google.com
-dupin@google.com
madym@google.com
+ngmatthew@google.com
roosa@google.com
shahrk@google.com
+sunnygoyal@google.com
+twickham@google.com
winsonc@google.com
diff --git a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
new file mode 100644
index 0000000..b517fc8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="#757575"
+ android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 97472a4..cf88ade 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -71,23 +71,19 @@
android:singleLine="true" />
</LinearLayout>
- <FrameLayout
+ <View
+ android:id="@+id/qs_drag_handle_view"
android:layout_width="24dp"
- android:layout_height="match_parent" >
- <View
- android:id="@+id/qs_drag_handle_view"
- android:layout_width="match_parent"
- android:layout_height="4dp"
- android:layout_marginTop="28dp"
- android:background="@drawable/qs_footer_drag_handle" />
- </FrameLayout>
+ android:layout_height="4dp"
+ android:layout_gravity="center"
+ android:background="@drawable/qs_footer_drag_handle" />
- <LinearLayout
+ <com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/qs_footer_actions_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:gravity="end" >
+ android:gravity="center_vertical|end" >
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
android:layout_width="48dp"
@@ -113,7 +109,7 @@
android:clipToPadding="false"
android:contentDescription="@string/accessibility_quick_settings_edit"
android:focusable="true"
- android:padding="16dp"
+ android:padding="15dp"
android:src="@drawable/ic_mode_edit"
android:tint="?android:attr/colorForeground"/>
@@ -131,6 +127,7 @@
android:layout_height="match_parent"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/accessibility_quick_settings_settings"
+ android:padding="15dp"
android:src="@drawable/ic_settings_16dp"
android:tint="?android:attr/colorForeground"/>
@@ -145,7 +142,7 @@
android:visibility="invisible"/>
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- </LinearLayout>
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a62f38b..d11ab42 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -230,7 +230,7 @@
<!-- The height of the quick settings footer that holds the user switcher, settings icon,
etc. -->
- <dimen name="qs_footer_height">48dp</dimen>
+ <dimen name="qs_footer_height">56dp</dimen>
<!-- The padding between the notifications and the quick settings container -->
<dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen>
@@ -337,7 +337,7 @@
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
<!-- Difference between drag handle margin in QQS and expanded QS -->
- <dimen name="qs_footer_drag_handle_offset">6dp</dimen>
+ <dimen name="qs_footer_drag_handle_offset">10dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
@@ -513,7 +513,7 @@
<dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
<!-- The width of user avatar when expanded -->
- <dimen name="multi_user_avatar_expanded_size">16dp</dimen>
+ <dimen name="multi_user_avatar_expanded_size">18dp</dimen>
<!-- The font size of the time when collapsed in QS -->
<dimen name="qs_time_collapsed_size">14sp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 4cf817e..b8319a8e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -44,4 +44,9 @@
* Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
*/
void setRecentsOnboardingText(CharSequence text);
+
+ /**
+ * Enables/disables launcher/overview interaction features {@link InteractionType}.
+ */
+ void setInteractionState(int flags);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index f622d4a..17191868 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -28,4 +28,33 @@
public static final int HIT_TARGET_NONE = 0;
public static final int HIT_TARGET_BACK = 1;
public static final int HIT_TARGET_HOME = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({FLAG_DISABLE_SWIPE_UP,
+ FLAG_DISABLE_QUICK_SCRUB,
+ FLAG_SHOW_OVERVIEW_BUTTON,
+ FLAG_HIDE_BACK_BUTTON
+ })
+ public @interface InteractionType {}
+
+ /**
+ * Interaction type: whether the gesture to swipe up from the navigation bar will trigger
+ * launcher to show overview
+ */
+
+ public static final int FLAG_DISABLE_SWIPE_UP = 0x1;
+ /**
+ * Interaction type: enable quick scrub and switch interaction on the home button
+ */
+ public static final int FLAG_DISABLE_QUICK_SCRUB = 0x2;
+
+ /**
+ * Interaction type: show/hide the overview button while this service is connected to launcher
+ */
+ public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4;
+
+ /**
+ * Interaction type: show/hide the back button while this service is connected to launcher
+ */
+ public static final int FLAG_HIDE_BACK_BUTTON = 0x8;
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index d0128ef..1185f45 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -47,6 +47,8 @@
import java.util.ArrayList;
import java.util.List;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+
/**
* Class to send information from overview to launcher with a binder.
*/
@@ -67,6 +69,7 @@
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private CharSequence mOnboardingText;
+ private @InteractionType int mInteractionFlags;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -108,6 +111,22 @@
public void setRecentsOnboardingText(CharSequence text) {
mOnboardingText = text;
}
+
+ public void setInteractionState(@InteractionType int flags) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (mInteractionFlags != flags) {
+ mInteractionFlags = flags;
+ mHandler.post(() -> {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
+ }
+ });
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
@@ -230,6 +249,10 @@
return mOnboardingText;
}
+ public int getInteractionFlags() {
+ return mInteractionFlags;
+ }
+
private void disconnectFromLauncherService() {
if (mOverviewProxy != null) {
mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
@@ -263,5 +286,6 @@
public interface OverviewProxyListener {
default void onConnectionChanged(boolean isConnected) {}
default void onRecentsAnimationStarted() {}
+ default void onInteractionFlagsChanged(@InteractionType int flags) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1aea5e7..259bff2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -688,7 +688,7 @@
}
private Action getLockdownAction() {
- return new SinglePressAction(R.drawable.ic_lock_lock,
+ return new SinglePressAction(com.android.systemui.R.drawable.ic_lock_lockdown,
R.string.global_action_lockdown) {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index fe3ffb9..b9919a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -174,7 +174,8 @@
.addFloat(mDivider, "alpha", 0, 1)
.addFloat(mCarrierText, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
- .addFloat(mDragHandle, "translationY", 0, -mDragHandleExpandOffset)
+ .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0)
+ .addFloat(mDragHandle, "alpha", 1, 0)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 11d20b2..ef44ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -77,11 +77,11 @@
mStatusBar = statusBar;
}
- public ActivityOptions getLaunchAnimation(
- ExpandableNotificationRow sourceNofitication) {
- AnimationRunner animationRunner = new AnimationRunner(sourceNofitication);
- return ActivityOptions.makeRemoteAnimation(
- new RemoteAnimationAdapter(animationRunner, 1000 /* Duration */, 0 /* delay */));
+ public RemoteAnimationAdapter getLaunchAnimation(
+ ExpandableNotificationRow sourceNotification) {
+ AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
+ return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
+ 0 /* statusBarTransitionDelay */);
}
public boolean isAnimationPending() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 72938c2..79c605e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -19,6 +19,7 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
@@ -71,7 +72,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
-import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -165,6 +165,11 @@
public void onRecentsAnimationStarted() {
mNavigationBarView.setRecentsAnimationStarted(true);
}
+
+ @Override
+ public void onInteractionFlagsChanged(@InteractionType int flags) {
+ mNavigationBarView.updateStates();
+ }
};
// ----- Fragment Lifecycle Callbacks -----
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 63f2ceb..8970ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -127,7 +127,7 @@
private boolean proxyMotionEvents(MotionEvent event) {
final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
- if (overviewProxy != null) {
+ if (overviewProxy != null && mNavigationBarView.isQuickStepSwipeUpEnabled()) {
mNavigationBarView.requestUnbufferedDispatch(event);
event.transform(mTransformGlobalMatrix);
try {
@@ -192,7 +192,7 @@
}
public void onDraw(Canvas canvas) {
- if (mOverviewProxyService.getProxy() != null) {
+ if (mNavigationBarView.isQuickScrubEnabled()) {
mQuickScrubController.onDraw(canvas);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 53dc814..cd4eb23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -40,6 +40,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
import android.util.Log;
@@ -76,6 +77,11 @@
import java.io.PrintWriter;
import java.util.function.Consumer;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
final static String TAG = "StatusBar/NavBarView";
@@ -372,6 +378,19 @@
return getRecentsButton().getVisibility() == View.VISIBLE;
}
+ public boolean isQuickStepSwipeUpEnabled() {
+ return mOverviewProxyService.getProxy() != null
+ && ((mOverviewProxyService.getInteractionFlags()
+ & FLAG_DISABLE_SWIPE_UP) == 0);
+ }
+
+ public boolean isQuickScrubEnabled() {
+ return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
+ && mOverviewProxyService.getProxy() != null && !isRecentsButtonVisible()
+ && ((mOverviewProxyService.getInteractionFlags()
+ & FLAG_DISABLE_QUICK_SCRUB) == 0);
+ }
+
private void updateCarModeIcons(Context ctx) {
mBackCarModeIcon = getDrawable(ctx,
R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -391,20 +410,20 @@
}
if (oldConfig.densityDpi != newConfig.densityDpi
|| oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
- final boolean proxyAvailable = mOverviewProxyService.getProxy() != null;
- mBackIcon = proxyAvailable
+ final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
+ mBackIcon = quickStepEnabled
? getDrawable(ctx, R.drawable.ic_sysbar_back_quick_step,
R.drawable.ic_sysbar_back_quick_step_dark)
: getDrawable(ctx, R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_dark);
mBackLandIcon = mBackIcon;
- mBackAltIcon = proxyAvailable
+ mBackAltIcon = quickStepEnabled
? getDrawable(ctx, R.drawable.ic_sysbar_back_ime_quick_step,
R.drawable.ic_sysbar_back_ime_quick_step_dark)
: getDrawable(ctx, R.drawable.ic_sysbar_back_ime,
R.drawable.ic_sysbar_back_ime_dark);
mBackAltLandIcon = mBackAltIcon;
- mHomeDefaultIcon = proxyAvailable
+ mHomeDefaultIcon = quickStepEnabled
? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step,
R.drawable.ic_sysbar_home_quick_step_dark)
: getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
@@ -555,9 +574,14 @@
disableBack = false;
disableRecent = false;
}
+
if (mOverviewProxyService.getProxy() != null) {
- // When overview is connected to the launcher service, disable the recents button
- disableRecent = true;
+ // When overview is connected to the launcher service, disable the recents button by
+ // default unless overwritten by interaction flags. Similar with the back button but
+ // shown by default.
+ final int flags = mOverviewProxyService.getInteractionFlags();
+ disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0;
+ disableBack |= (flags & FLAG_HIDE_BACK_BUTTON) != 0;
}
ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
@@ -635,6 +659,11 @@
updateSlippery();
}
+ public void updateStates() {
+ updateSlippery();
+ setDisabledFlags(mDisabledFlags, true);
+ }
+
private void updateSlippery() {
setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
}
@@ -794,9 +823,8 @@
}
public void onOverviewProxyConnectionChanged(boolean isConnected) {
- setSlippery(!isConnected);
- setDisabledFlags(mDisabledFlags, true);
- setUpSwipeUpOnboarding(isConnected);
+ updateStates();
+ setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
setNavigationIconHints(mNavigationIconHints, true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index bb2f597..0bf01b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -29,15 +29,12 @@
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -89,6 +86,7 @@
private int mLightTrackColor;
private int mDarkTrackColor;
private float mDarkIntensity;
+ private View mHomeButtonView;
private final Handler mHandler = new Handler();
private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
@@ -114,11 +112,10 @@
if (!mQuickScrubActive) {
pos = mDragPositive ? Math.min((int) mTranslation, pos) : Math.max((int) mTranslation, pos);
}
- final View homeView = mNavigationBarView.getHomeButton().getCurrentView();
if (mIsVertical) {
- homeView.setTranslationY(pos);
+ mHomeButtonView.setTranslationY(pos);
} else {
- homeView.setTranslationX(pos);
+ mHomeButtonView.setTranslationX(pos);
}
};
@@ -126,6 +123,7 @@
@Override
public void onAnimationEnd(Animator animation) {
mNavigationBarView.getHomeButton().setClickable(true);
+ mHomeButtonView = null;
mQuickScrubActive = false;
mTranslation = 0;
}
@@ -137,8 +135,9 @@
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
- if (!isQuickScrubEnabled() || mQuickScrubActive || !mAllowQuickSwitch ||
- mNavigationBarView.getDownHitTarget() != HIT_TARGET_HOME) {
+ if (!mNavigationBarView.isQuickScrubEnabled() || mQuickScrubActive
+ || !mAllowQuickSwitch
+ || mNavigationBarView.getDownHitTarget() != HIT_TARGET_HOME) {
return false;
}
float velocityX = mIsRTL ? -velX : velX;
@@ -195,9 +194,8 @@
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
- if (overviewProxy == null) {
+ if (!mNavigationBarView.isQuickScrubEnabled()) {
homeButton.setDelayTouchFeedback(false);
return false;
}
@@ -226,7 +224,8 @@
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
- if (isQuickScrubEnabled()
+ mHomeButtonView = homeButton.getCurrentView();
+ if (mNavigationBarView.isQuickScrubEnabled()
&& mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
mTouchDownX = x;
mTouchDownY = y;
@@ -294,7 +293,7 @@
: Utilities.clamp(offset - mDownOffset, 0, trackSize);
if (mQuickScrubActive) {
try {
- overviewProxy.onQuickScrubProgress(scrubFraction);
+ mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
}
@@ -305,9 +304,9 @@
mTranslation /= SWITCH_STICKINESS;
}
if (mIsVertical) {
- homeButton.getCurrentView().setTranslationY(mTranslation);
+ mHomeButtonView.setTranslationY(mTranslation);
} else {
- homeButton.getCurrentView().setTranslationX(mTranslation);
+ mHomeButtonView.setTranslationX(mTranslation);
}
}
}
@@ -315,7 +314,7 @@
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- endQuickScrub();
+ endQuickScrub(true /* animate */);
break;
}
return mDraggingActive || mQuickScrubActive;
@@ -357,6 +356,11 @@
@Override
public void setBarState(boolean isVertical, boolean isRTL) {
+ final boolean changed = (mIsVertical != isVertical) || (mIsRTL != isRTL);
+ if (changed) {
+ // End quickscrub if the state changes mid-transition
+ endQuickScrub(false /* animate */);
+ }
mIsVertical = isVertical;
mIsRTL = isRTL;
try {
@@ -370,10 +374,6 @@
}
}
- boolean isQuickScrubEnabled() {
- return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true);
- }
-
private void startQuickScrub() {
if (!mQuickScrubActive) {
mQuickScrubActive = true;
@@ -392,7 +392,7 @@
}
}
- private void endQuickScrub() {
+ private void endQuickScrub(boolean animate) {
mHandler.removeCallbacks(mLongPressRunnable);
if (mDraggingActive || mQuickScrubActive) {
mButtonAnimator.setIntValues((int) mTranslation, 0);
@@ -406,6 +406,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to send end of quick scrub.", e);
}
+ if (!animate) {
+ mQuickScrubEndAnimator.end();
+ }
}
mDraggingActive = false;
}
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 94ebc1b..2b50853 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -138,8 +138,7 @@
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
- // Assuming the shade is expanded during initialization
- private float mExpansionFraction = 1f;
+ private float mFraction;
private boolean mDarkenWhileDragging;
protected boolean mAnimateChange;
@@ -253,7 +252,6 @@
mCurrentBehindTint = state.getBehindTint();
mCurrentInFrontAlpha = state.getFrontAlpha();
mCurrentBehindAlpha = state.getBehindAlpha();
- applyExpansionToAlpha();
// Cancel blanking transitions that were pending before we requested a new state
if (mPendingFrameCallback != null) {
@@ -365,50 +363,45 @@
* @param fraction From 0 to 1 where 0 means collapse and 1 expanded.
*/
public void setPanelExpansion(float fraction) {
- if (mExpansionFraction != fraction) {
- mExpansionFraction = fraction;
+ if (mFraction != fraction) {
+ mFraction = fraction;
- if (!(mState == ScrimState.UNLOCKED || mState == ScrimState.KEYGUARD)) {
- return;
- }
+ if (mState == ScrimState.UNLOCKED) {
+ // Darken scrim as you pull down the shade when unlocked
+ float behindFraction = getInterpolatedFraction();
+ behindFraction = (float) Math.pow(behindFraction, 0.8f);
+ mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
+ mCurrentInFrontAlpha = 0;
+ } else if (mState == ScrimState.KEYGUARD) {
+ if (mUpdatePending) {
+ return;
+ }
- applyExpansionToAlpha();
-
- if (mUpdatePending) {
+ // Either darken of make the scrim transparent when you
+ // pull down the shade
+ float interpolatedFract = getInterpolatedFraction();
+ if (mDarkenWhileDragging) {
+ mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking,
+ mScrimBehindAlphaKeyguard, interpolatedFract);
+ mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
+ } else {
+ mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, mScrimBehindAlphaKeyguard,
+ interpolatedFract);
+ mCurrentInFrontAlpha = 0;
+ }
+ } else {
return;
}
if (mPinnedHeadsUpCount != 0) {
updateHeadsUpScrim(false);
}
+
updateScrim(false /* animate */, mScrimInFront, mCurrentInFrontAlpha);
updateScrim(false /* animate */, mScrimBehind, mCurrentBehindAlpha);
}
}
- private void applyExpansionToAlpha() {
- if (mState == ScrimState.UNLOCKED) {
- // Darken scrim as you pull down the shade when unlocked
- float behindFraction = getInterpolatedFraction();
- behindFraction = (float) Math.pow(behindFraction, 0.8f);
- mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
- mCurrentInFrontAlpha = 0;
- } else if (mState == ScrimState.KEYGUARD) {
- // Either darken of make the scrim transparent when you
- // pull down the shade
- float interpolatedFract = getInterpolatedFraction();
- if (mDarkenWhileDragging) {
- mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking,
- mScrimBehindAlphaKeyguard, interpolatedFract);
- mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
- } else {
- mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, mScrimBehindAlphaKeyguard,
- interpolatedFract);
- mCurrentInFrontAlpha = 0;
- }
- }
- }
-
/**
* Keyguard and shade scrim opacity varies according to how many notifications are visible.
* @param notificationCount Number of visible notifications.
@@ -504,7 +497,7 @@
}
private float getInterpolatedFraction() {
- float frac = mExpansionFraction;
+ float frac = mFraction;
// let's start this 20% of the way down the screen
frac = frac * 1.2f - 0.2f;
if (frac <= 0) {
@@ -834,7 +827,7 @@
} else {
alpha = 1.0f - mTopHeadsUpDragAmount;
}
- float expandFactor = (1.0f - mExpansionFraction);
+ float expandFactor = (1.0f - mFraction);
expandFactor = Math.max(expandFactor, 0.0f);
return alpha * expandFactor;
}
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 3b63d6c..24920cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -111,6 +111,7 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
@@ -2849,7 +2850,7 @@
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
int result = ActivityManager.START_CANCELED;
ActivityOptions options = new ActivityOptions(getActivityOptions(
- null /* sourceNotification */));
+ null /* remoteAnimation */));
options.setDisallowEnterPictureInPictureWhileLaunching(
disallowEnterPictureInPictureWhileLaunching);
if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
@@ -5001,11 +5002,15 @@
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
remoteInputText.toString());
}
+ RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
+ row);
try {
+ ActivityManager.getService().registerRemoteAnimationForNextActivityStart(
+ intent.getCreatorPackage(), adapter);
launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
- null, null, getActivityOptions(row));
+ null, null, getActivityOptions(adapter));
mActivityLaunchAnimator.setLaunchResult(launchResult);
- } catch (PendingIntent.CanceledException e) {
+ } catch (RemoteException | PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
Log.w(TAG, "Sending contentIntent failed: " + e);
@@ -5165,7 +5170,8 @@
AsyncTask.execute(() -> {
int launchResult = TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(row),
+ .startActivities(getActivityOptions(
+ mActivityLaunchAnimator.getLaunchAnimation(row)),
new UserHandle(UserHandle.getUserId(appUid)));
mActivityLaunchAnimator.setLaunchResult(launchResult);
if (shouldCollapse()) {
@@ -5300,7 +5306,7 @@
}
try {
intent.send(null, 0, null, null, null, null, getActivityOptions(
- null /* sourceNotification */));
+ null /* animationAdapter */));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -5328,10 +5334,10 @@
return true;
}
- protected Bundle getActivityOptions(ExpandableNotificationRow sourceNotification) {
+ protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
ActivityOptions options;
- if (sourceNotification != null) {
- options = mActivityLaunchAnimator.getLaunchAnimation(sourceNotification);
+ if (animationAdapter != null) {
+ options = ActivityOptions.makeRemoteAnimation(animationAdapter);
} else {
options = ActivityOptions.makeBasic();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 4702793..43e16db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -180,7 +180,6 @@
@Test
public void transitionToUnlocked() {
- mScrimController.setPanelExpansion(0f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
@@ -198,7 +197,6 @@
public void transitionToUnlockedFromAod() {
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.AOD);
- mScrimController.setPanelExpansion(0f);
mScrimController.finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
// Immediately tinted after the transition starts
@@ -326,23 +324,6 @@
verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
}
- @Test
- public void testConservesExpansionOpacityAfterTransition() {
- mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.5f);
- mScrimController.finishAnimationsImmediately();
-
- final float expandedAlpha = mScrimBehind.getViewAlpha();
-
- mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
- mScrimController.finishAnimationsImmediately();
- mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertEquals("Scrim expansion opacity wasn't conserved when transitioning back",
- expandedAlpha, mScrimBehind.getViewAlpha(), 0.01f);
- }
-
private void assertScrimTint(ScrimView scrimView, boolean tinted) {
final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT;
final String name = scrimView == mScrimInFront ? "front" : "back";
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ae5e133..7eebf5a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5213,6 +5213,22 @@
// OS: P
ACTION_OUTPUT_CHOOSER_DISCONNECT = 1297;
+ // OPEN: TV Settings > Home theater control
+ // OS: P
+ SETTINGS_TV_HOME_THEATER_CONTROL_CATEGORY = 1298;
+
+ // OPEN: TV Settings > TV Inputs (Inputs & Devices)
+ // OS: P
+ SETTINGS_TV_INPUTS_CATEGORY = 1299;
+
+ // OPEN: TV Settings > Device
+ // OS: P
+ SETTINGS_TV_DEVICE_CATEGORY = 1300;
+
+ // OPEN: TV Settings > Network > Proxy settings
+ // OS: P
+ DIALOG_TV_NETWORK_PROXY = 1301;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index c36bb6d..5b5d18f 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -446,8 +446,10 @@
mMagnificationRegion.getBounds(viewport);
final MagnificationSpec spec = mCurrentMagnificationSpec;
final float oldScale = spec.scale;
- final float oldCenterX = (viewport.width() / 2.0f - spec.offsetX) / oldScale;
- final float oldCenterY = (viewport.height() / 2.0f - spec.offsetY) / oldScale;
+ 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);
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 52ab85c..6c6dd5b 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -402,9 +402,9 @@
com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
scaleValue, false);
mScalingThreshold = scaleValue.getFloat();
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
mScaleGestureDetector.setQuickScaleEnabled(false);
- mScrollGestureDetector = new GestureDetector(context, this);
+ mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
}
@Override
@@ -638,7 +638,7 @@
@VisibleForTesting boolean mShortcutTriggered;
- @VisibleForTesting Handler mHandler = new Handler(this);
+ @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper(), this);
public DetectingState(Context context) {
mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
@@ -654,7 +654,9 @@
final int type = message.what;
switch (type) {
case MESSAGE_ON_TRIPLE_TAP_AND_HOLD: {
- onTripleTapAndHold(/* down */ (MotionEvent) message.obj);
+ MotionEvent down = (MotionEvent) message.obj;
+ transitionToViewportDraggingStateAndClear(down);
+ down.recycle();
}
break;
case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
@@ -720,8 +722,7 @@
// over insta-delegating on 3tap&swipe
// (which is a rare combo to be used aside from magnification)
if (isMultiTapTriggered(2 /* taps */)) {
- transitionTo(mViewportDraggingState);
- clear();
+ transitionToViewportDraggingStateAndClear(event);
} else {
transitionToDelegatingStateAndClear();
}
@@ -806,7 +807,8 @@
/** -> {@link ViewportDraggingState} */
public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) {
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
+ mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD,
+ MotionEvent.obtain(event)),
ViewConfiguration.getLongPressTimeout());
}
@@ -890,7 +892,7 @@
}
}
- void onTripleTapAndHold(MotionEvent down) {
+ void transitionToViewportDraggingStateAndClear(MotionEvent down) {
if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
clear();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index d5a722b..4b3abea 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -24,7 +24,6 @@
import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -56,7 +55,12 @@
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -84,6 +88,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Entry point service for autofill management.
@@ -98,6 +103,8 @@
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
+ private static final char COMPAT_PACKAGE_DELIMITER = ':';
+
private final Context mContext;
private final AutoFillUI mUi;
@@ -123,6 +130,9 @@
private final LocalLog mUiLatencyHistory = new LocalLog(20);
private final LocalLog mWtfHistory = new LocalLog(50);
+ private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+ private final LocalService mLocalService = new LocalService();
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -271,7 +281,7 @@
@Override
public void onStart() {
publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
- publishLocalService(AutofillManagerInternal.class, new LocalService());
+ publishLocalService(AutofillManagerInternal.class, mLocalService);
}
@Override
@@ -317,6 +327,11 @@
mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
mDisabledUsers.get(resolvedUserId));
mServicesCache.put(userId, service);
+ final ArrayMap<String, Pair<Long, String>> compatPackages =
+ service.getCompatibilityPackagesLocked();
+ if (compatPackages != null) {
+ addCompatibilityModeRequests(compatPackages, userId);
+ }
}
return service;
}
@@ -482,6 +497,7 @@
if (service != null) {
mServicesCache.delete(userId);
service.destroyLocked();
+ mAutofillCompatState.removeCompatibilityModeRequests(userId);
}
}
@@ -498,18 +514,60 @@
*/
@GuardedBy("mLock")
private void updateCachedServiceLocked(int userId, boolean disabled) {
- AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
service.destroySessionsLocked();
service.updateLocked(disabled);
if (!service.isEnabledLocked()) {
removeCachedServiceLocked(userId);
+ } else {
+ final ArrayMap<String, Pair<Long, String>> compatPackages =
+ service.getCompatibilityPackagesLocked();
+ if (compatPackages != null) {
+ addCompatibilityModeRequests(compatPackages, userId);
+ }
}
}
}
- private final class LocalService extends AutofillManagerInternal {
+ private void addCompatibilityModeRequests(
+ @NonNull ArrayMap<String, Pair<Long, String>> compatPackages, int userId) {
+ final Set<String> whiteListedPackages = Build.IS_ENG ? null
+ : getWhitelistedCompatModePackages();
+ final int compatPackageCount = compatPackages.size();
+ for (int i = 0; i < compatPackageCount; i++) {
+ final String packageName = compatPackages.keyAt(i);
+ if (!Build.IS_ENG && (whiteListedPackages == null
+ || !whiteListedPackages.contains(packageName))) {
+ Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
+ continue;
+ }
+ final Long maxVersionCode = compatPackages.valueAt(i).first;
+ if (maxVersionCode != null) {
+ mAutofillCompatState.addCompatibilityModeRequest(packageName,
+ maxVersionCode, userId);
+ }
+ }
+ }
+ private @Nullable Set<String> getWhitelistedCompatModePackages() {
+ final String compatPackagesSetting = Settings.Global.getString(
+ mContext.getContentResolver(),
+ Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+ if (TextUtils.isEmpty(compatPackagesSetting)) {
+ return null;
+ }
+ final Set<String> compatPackages = new ArraySet<>();
+ final SimpleStringSplitter splitter = new SimpleStringSplitter(
+ COMPAT_PACKAGE_DELIMITER);
+ splitter.setString(compatPackagesSetting);
+ while (splitter.hasNext()) {
+ compatPackages.add(splitter.next());
+ }
+ return compatPackages;
+ }
+
+ private final class LocalService extends AutofillManagerInternal {
@Override
public void onBackKeyPressed() {
if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
@@ -519,13 +577,59 @@
@Override
public boolean isCompatibilityModeRequested(@NonNull String packageName,
long versionCode, @UserIdInt int userId) {
+ return mAutofillCompatState.isCompatibilityModeRequested(
+ packageName, versionCode, userId);
+ }
+ }
+
+ private static class AutofillCompatState {
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private SparseArray<ArrayMap<String, Long>> mUserSpecs;
+
+ boolean isCompatibilityModeRequested(@NonNull String packageName,
+ long versionCode, @UserIdInt int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- return service.isCompatibilityModeRequestedLocked(packageName, versionCode);
+ if (mUserSpecs == null) {
+ return false;
+ }
+ final ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ return false;
+ }
+ final Long maxVersionCode = userSpec.get(packageName);
+ if (maxVersionCode == null) {
+ return false;
+ }
+ return versionCode <= maxVersionCode;
+ }
+ }
+
+ void addCompatibilityModeRequest(@NonNull String packageName,
+ long versionCode, @UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs == null) {
+ mUserSpecs = new SparseArray<>();
+ }
+ ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ userSpec = new ArrayMap<>();
+ mUserSpecs.put(userId, userSpec);
+ }
+ userSpec.put(packageName, versionCode);
+ }
+ }
+
+ void removeCompatibilityModeRequests(@UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs != null) {
+ mUserSpecs.remove(userId);
+ if (mUserSpecs.size() <= 0) {
+ mUserSpecs = null;
+ }
}
}
- return false;
}
}
@@ -580,7 +684,7 @@
@Override
public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
- ComponentName componentName) {
+ ComponentName componentName, boolean compatMode) {
activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
@@ -599,7 +703,7 @@
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
- autofillId, bounds, value, hasCallback, flags, componentName);
+ autofillId, bounds, value, hasCallback, flags, componentName, compatMode);
}
}
@@ -770,7 +874,7 @@
public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
boolean hasCallback, int flags, ComponentName componentName, int sessionId,
- int action) {
+ int action, boolean compatMode) {
boolean restart = false;
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
@@ -783,7 +887,7 @@
}
if (restart) {
return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
- hasCallback, flags, componentName);
+ hasCallback, flags, componentName, compatMode);
}
// Nothing changed...
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 2dcc6da..31f2933 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -64,6 +64,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -220,6 +221,17 @@
return mInfo.getServiceInfo().applicationInfo.uid;
}
+
+ @GuardedBy("mLock")
+ @Nullable
+ String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) {
+ if (mInfo == null) {
+ Slog.w(TAG, "getUrlBarResourceIdForCompatModeLocked(): no mInfo");
+ return null;
+ }
+ return mInfo.getUrlBarResourceId(packageName);
+ }
+
@Nullable
String getServicePackageName() {
final ComponentName serviceComponent = getServiceComponentName();
@@ -345,7 +357,7 @@
int startSessionLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
@NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
- int flags, @NonNull ComponentName componentName) {
+ int flags, @NonNull ComponentName componentName, boolean compatMode) {
if (!isEnabledLocked()) {
return 0;
}
@@ -375,7 +387,7 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, componentName, flags);
+ hasCallback, componentName, compatMode, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -481,7 +493,7 @@
@GuardedBy("mLock")
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, boolean hasCallback,
- @NonNull ComponentName componentName, int flags) {
+ @NonNull ComponentName componentName, boolean compatMode, int flags) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -499,7 +511,8 @@
final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
- mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
+ mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode,
+ flags);
mSessions.put(newSession.id, newSession);
return newSession;
@@ -894,7 +907,10 @@
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
- pw.print(prefix); pw.print("Compat pkgs: "); pw.println(getWhitelistedCompatModePackages());
+ final ArrayMap<String, Pair<Long, String>> compatPkgs = getCompatibilityPackagesLocked();
+ if (compatPkgs != null) {
+ pw.print(prefix); pw.print("Compat pkgs: "); pw.println(compatPkgs.keySet());
+ }
pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
@@ -1018,23 +1034,11 @@
}
@GuardedBy("mLock")
- boolean isCompatibilityModeRequestedLocked(@NonNull String packageName,
- long versionCode) {
- if (mInfo == null || !mInfo.isCompatibilityModeRequested(packageName, versionCode)) {
- return false;
+ @Nullable ArrayMap<String, Pair<Long, String>> getCompatibilityPackagesLocked() {
+ if (mInfo != null) {
+ return mInfo.getCompatibilityPackages();
}
- if (!Build.IS_ENG) {
- // TODO: Build a map and watch for settings changes (this is called on app start)
- final String whiteListedPackages = getWhitelistedCompatModePackages();
- return whiteListedPackages != null && whiteListedPackages.contains(packageName);
- }
- return true;
- }
-
- private String getWhitelistedCompatModePackages() {
- return Settings.Global.getString(
- mContext.getContentResolver(),
- Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+ return null;
}
private void sendStateToClients(boolean resetClient) {
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 02a62e1..5ef467d 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -18,11 +18,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
@@ -31,11 +34,14 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.Objects;
import java.util.Set;
public final class Helper {
+ private static final String TAG = "AutofillHelper";
+
/**
* Defines a logging flag that can be dynamically changed at runtime using
* {@code cmd autofill set log_level debug}.
@@ -121,4 +127,61 @@
pw.print(text.length()); pw.println("_chars");
}
}
+
+ /**
+ * Finds the {@link ViewNode} that has the requested {@code autofillId}, if any.
+ */
+ @Nullable
+ public static ViewNode findViewNodeByAutofillId(@NonNull AssistStructure structure,
+ @NonNull AutofillId autofillId) {
+ return findViewNode(structure, (node) -> {
+ return autofillId.equals(node.getAutofillId());
+ });
+ }
+
+ private static ViewNode findViewNode(@NonNull AssistStructure structure,
+ @NonNull ViewNodeFilter filter) {
+ final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
+ final int numWindowNodes = structure.getWindowNodeCount();
+ for (int i = 0; i < numWindowNodes; i++) {
+ nodesToProcess.add(structure.getWindowNodeAt(i).getRootViewNode());
+ }
+ while (!nodesToProcess.isEmpty()) {
+ final ViewNode node = nodesToProcess.removeFirst();
+ if (filter.matches(node)) {
+ return node;
+ }
+ for (int i = 0; i < node.getChildCount(); i++) {
+ nodesToProcess.addLast(node.getChildAt(i));
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Sanitize the {@code webDomain} property of the URL bar node on compat mode.
+ */
+ public static void sanitizeUrlBar(@NonNull AssistStructure structure,
+ @NonNull String urlBarId) {
+ final ViewNode urlBarNode = findViewNode(structure, (node) -> {
+ return urlBarId.equals(node.getIdEntry());
+ });
+ if (urlBarNode != null) {
+ final String domain = urlBarNode.getText().toString();
+ if (domain.isEmpty()) {
+ if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId);
+ return;
+ }
+ urlBarNode.setWebDomain(domain);
+ if (sDebug) {
+ Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain="
+ + urlBarNode.getWebDomain());
+ }
+ }
+ }
+
+ private interface ViewNodeFilter {
+ boolean matches(ViewNode node);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4a24704..55c36b0 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -140,6 +140,9 @@
/** Component that's being auto-filled */
@NonNull private final ComponentName mComponentName;
+ /** Whether the app being autofilled is running in compat mode. */
+ private final boolean mCompatMode;
+
@GuardedBy("mLock")
private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
@@ -263,6 +266,15 @@
componentNameFromApp == null ? "null"
: componentNameFromApp.flattenToShortString()));
}
+ if (mCompatMode) {
+ // Sanitize URL bar, if needed
+ final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked(
+ mComponentName.getPackageName());
+ if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId);
+ if (urlBarId != null) {
+ Helper.sanitizeUrlBar(structure, urlBarId);
+ }
+ }
structure.sanitizeForParceling(true);
// Flags used to start the session.
@@ -476,7 +488,7 @@
@NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
@NonNull LocalLog wtfHistory,
@NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
- int flags) {
+ boolean compatMode, int flags) {
id = sessionId;
mFlags = flags;
this.uid = uid;
@@ -491,6 +503,7 @@
mUiLatencyHistory = uiLatencyHistory;
mWtfHistory = wtfHistory;
mComponentName = componentName;
+ mCompatMode = compatMode;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
@@ -1537,7 +1550,7 @@
final int numContexts = mContexts.size();
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = context.findViewNodeByAutofillId(id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
if (node != null) {
final AutofillValue value = node.getAutofillValue();
if (sDebug) {
@@ -1561,7 +1574,7 @@
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = context.findViewNodeByAutofillId(id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
if (node != null && node.getAutofillOptions() != null) {
return node.getAutofillOptions();
}
@@ -2288,6 +2301,7 @@
pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
pw.print(prefix); pw.print("mClientState: "); pw.println(
Helper.bundleToString(mClientState));
+ pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
mRemoteFillService.dump(prefix, pw);
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index bdeb231..7cd007b 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -120,7 +120,6 @@
import android.service.vr.IVrStateCallbacks;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -183,7 +182,6 @@
public class InputMethodManagerService extends IInputMethodManager.Stub
implements ServiceConnection, Handler.Callback {
static final boolean DEBUG = false;
- static final boolean DEBUG_RESTORE = DEBUG || false;
static final String TAG = "InputMethodManagerService";
@Retention(SOURCE)
@@ -911,15 +909,6 @@
|| Intent.ACTION_USER_REMOVED.equals(action)) {
updateCurrentProfileIds();
return;
- } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
- final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Settings.Secure.ENABLED_INPUT_METHODS.equals(name)) {
- final String prevValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_PREVIOUS_VALUE);
- final String newValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_NEW_VALUE);
- restoreEnabledInputMethods(mContext, prevValue, newValue);
- }
} else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
onActionLocaleChanged();
} else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
@@ -984,44 +973,6 @@
}
}
- // Apply the results of a restore operation to the set of enabled IMEs. Note that this
- // does not attempt to validate on the fly with any installed device policy, so must only
- // be run in the context of initial device setup.
- //
- // TODO: Move this method to InputMethodUtils with adding unit tests.
- static void restoreEnabledInputMethods(Context context, String prevValue, String newValue) {
- if (DEBUG_RESTORE) {
- Slog.i(TAG, "Restoring enabled input methods:");
- Slog.i(TAG, "prev=" + prevValue);
- Slog.i(TAG, " new=" + newValue);
- }
- // 'new' is the just-restored state, 'prev' is what was in settings prior to the restore
- ArrayMap<String, ArraySet<String>> prevMap =
- InputMethodUtils.parseInputMethodsAndSubtypesString(prevValue);
- ArrayMap<String, ArraySet<String>> newMap =
- InputMethodUtils.parseInputMethodsAndSubtypesString(newValue);
-
- // Merge the restored ime+subtype enabled states into the live state
- for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) {
- final String imeId = entry.getKey();
- ArraySet<String> prevSubtypes = prevMap.get(imeId);
- if (prevSubtypes == null) {
- prevSubtypes = new ArraySet<>(2);
- prevMap.put(imeId, prevSubtypes);
- }
- prevSubtypes.addAll(entry.getValue());
- }
-
- final String mergedImesAndSubtypesString =
- InputMethodUtils.buildInputMethodsAndSubtypesString(prevMap);
- if (DEBUG_RESTORE) {
- Slog.i(TAG, "Merged IME string:");
- Slog.i(TAG, " " + mergedImesAndSubtypesString);
- }
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString);
- }
-
final class MyPackageMonitor extends PackageMonitor {
/**
* Package names that are known to contain {@link InputMethodService}.
@@ -1577,7 +1528,6 @@
broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
- broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
broadcastFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
broadcastFilter.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e8b7839..d488e6f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -380,6 +380,7 @@
import android.view.Gravity;
import android.view.IRecentsAnimationRunner;
import android.view.LayoutInflater;
+import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.View;
import android.view.WindowManager;
@@ -11362,9 +11363,6 @@
throw new IllegalArgumentException("Invalid task, not in foreground");
}
- // When a task is locked, dismiss the pinned stack if it exists
- mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
-
// {@code isSystemCaller} is used to distinguish whether this request is initiated by the
// system or a specific app.
// * System-initiated requests will only start the pinned mode (screen pinning)
@@ -11374,6 +11372,9 @@
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
+ // When a task is locked, dismiss the pinned stack if it exists
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
+
mLockTaskController.startLockTaskMode(task, isSystemCaller, callingUid);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -26336,4 +26337,20 @@
}
}
}
+
+ @Override
+ public void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) throws RemoteException {
+ enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ "registerRemoteAnimationForNextActivityStart");
+ synchronized (this) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mActivityStartController.registerRemoteAnimationForNextActivityStart(packageName,
+ adapter);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9838851..ddba349 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -380,8 +380,9 @@
}
String getLifecycleDescription(String reason) {
- return "component:" + intent.getComponent().flattenToShortString() + ", state=" + state
- + ", reason=" + reason + ", time=" + System.currentTimeMillis();
+ return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
+ + ", package=" + packageName + ", state=" + state + ", reason=" + reason + ", time="
+ + System.currentTimeMillis();
}
void dump(PrintWriter pw, String prefix) {
@@ -2583,7 +2584,8 @@
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(getLifecycleDescription("relaunchActivityLocked"));
}
final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
transaction.addCallback(callbackItem);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 055a1aa..812de88 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1444,7 +1444,8 @@
mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(prev.finishing, userLeaving,
- prev.configChangeFlags, pauseImmediately));
+ prev.configChangeFlags, pauseImmediately).setDescription(
+ prev.getLifecycleDescription("startPausingLocked")));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
@@ -1524,7 +1525,8 @@
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
- finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
+ "activityPausedLocked");
}
}
}
@@ -1541,7 +1543,8 @@
prev.state = ActivityState.PAUSED;
if (prev.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
- prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
+ prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
+ "completedPausedLocked");
} else if (prev.app != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
@@ -3673,8 +3676,8 @@
final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
: FINISH_AFTER_PAUSE;
- final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj)
- == null;
+ final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
+ "finishActivityLocked") == null;
// The following code is an optimization. When the last non-task overlay activity
// is removed from the task, we remove the entire task from the stack. However,
@@ -3715,7 +3718,8 @@
static final int FINISH_AFTER_PAUSE = 1;
static final int FINISH_AFTER_VISIBLE = 2;
- final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
+ final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj,
+ String reason) {
// First things first: if this activity is currently visible,
// and the resumed activity is not yet visible, then hold off on
// finishing until the resumed one becomes visible.
@@ -3758,7 +3762,7 @@
|| prevState == STOPPED
|| prevState == ActivityState.INITIALIZING) {
r.makeFinishingLocked();
- boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
+ boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
if (finishingActivityInNonFocusedStack) {
// Finishing activity that was in paused state and it was in not currently focused
@@ -3794,7 +3798,8 @@
continue;
}
Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r + " immediately");
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+ "finishAllActivitiesLocked");
}
}
if (noActivitiesInStack) {
@@ -4882,7 +4887,8 @@
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+ "handleAppCrashedLocked");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4928e90..5c30764 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1453,7 +1453,8 @@
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward())
.setDescription(r.getLifecycleDescription("realStartActivityLocked"));
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(r.getLifecycleDescription("realStartActivityLocked"));
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
@@ -1955,7 +1956,8 @@
final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
- stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
+ stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
+ "activityIdleInternalLocked");
} else {
stack.stopActivityLocked(r);
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index da11f68..868f90d 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -41,6 +41,7 @@
import android.os.Message;
import android.provider.Settings;
import android.util.Slog;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
@@ -85,6 +86,8 @@
private final Handler mHandler;
+ private final PendingRemoteAnimationRegistry mPendingRemoteAnimationRegistry;
+
private final class StartHandler extends Handler {
public StartHandler(Looper looper) {
super(looper, null, true);
@@ -123,6 +126,8 @@
mHandler = new StartHandler(mService.mHandlerThread.getLooper());
mFactory = factory;
mFactory.setController(this);
+ mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service,
+ service.mHandler);
}
/**
@@ -399,6 +404,15 @@
return mPendingActivityLaunches.size() < pendingLaunches;
}
+ void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) {
+ mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter);
+ }
+
+ PendingRemoteAnimationRegistry getPendingRemoteAnimationRegistry() {
+ return mPendingRemoteAnimationRegistry;
+ }
+
void dump(PrintWriter pw, String prefix, String dumpPackage) {
pw.print(prefix);
pw.print("mLastHomeActivityStartResult=");
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 055b89b..0dcefbf 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -708,6 +708,8 @@
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor)
: null;
+ checkedOptions = mService.getActivityStartController().getPendingRemoteAnimationRegistry()
+ .overrideOptionsIfNeeded(callingPackage, checkedOptions);
if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index ef82f36..fba0377 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -43,7 +43,10 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
@@ -65,12 +68,13 @@
// There is some accuracy error in wifi reports so allow some slop in the results.
private static final long MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS = 750;
- private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor(
- (ThreadFactory) r -> {
- Thread t = new Thread(r, "batterystats-worker");
- t.setPriority(Thread.NORM_PRIORITY);
- return t;
- });
+ private final ScheduledExecutorService mExecutorService =
+ Executors.newSingleThreadScheduledExecutor(
+ (ThreadFactory) r -> {
+ Thread t = new Thread(r, "batterystats-worker");
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ });
private final Context mContext;
private final BatteryStatsImpl mStats;
@@ -85,8 +89,20 @@
private String mCurrentReason = null;
@GuardedBy("this")
+ private boolean mOnBattery;
+
+ @GuardedBy("this")
+ private boolean mOnBatteryScreenOff;
+
+ @GuardedBy("this")
+ private boolean mUseLatestStates = true;
+
+ @GuardedBy("this")
private final IntArray mUidsToRemove = new IntArray();
+ @GuardedBy("this")
+ private Future<?> mWakelockChangesUpdate;
+
private final Object mWorkerLock = new Object();
@GuardedBy("mWorkerLock")
@@ -157,6 +173,50 @@
return null;
}
+ @Override
+ public Future<?> scheduleCpuSyncDueToScreenStateChange(
+ boolean onBattery, boolean onBatteryScreenOff) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) {
+ mOnBattery = onBattery;
+ mOnBatteryScreenOff = onBatteryScreenOff;
+ mUseLatestStates = false;
+ }
+ return scheduleSyncLocked("screen-state", UPDATE_CPU);
+ }
+ }
+
+ @Override
+ public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
+ if (mExecutorService.isShutdown()) {
+ return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ }
+
+ if (mWakelockChangesUpdate != null) {
+ // If there's already a scheduled task, leave it as is if we're trying to re-schedule
+ // it again with a delay, otherwise cancel and re-schedule it.
+ if (delayMillis == 0) {
+ mWakelockChangesUpdate.cancel(false);
+ } else {
+ return mWakelockChangesUpdate;
+ }
+ }
+
+ mWakelockChangesUpdate = mExecutorService.schedule(() -> {
+ scheduleSync("wakelock-change", UPDATE_CPU);
+ scheduleRunnable(() -> mStats.postBatteryNeedsCpuUpdateMsg());
+ mWakelockChangesUpdate = null;
+ }, delayMillis, TimeUnit.MILLISECONDS);
+ return mWakelockChangesUpdate;
+ }
+
+ @Override
+ public void cancelCpuSyncDueToWakelockChange() {
+ if (mWakelockChangesUpdate != null) {
+ mWakelockChangesUpdate.cancel(false);
+ }
+ }
+
public synchronized Future<?> scheduleWrite() {
if (mExecutorService.isShutdown()) {
return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
@@ -204,14 +264,21 @@
final int updateFlags;
final String reason;
final int[] uidsToRemove;
+ final boolean onBattery;
+ final boolean onBatteryScreenOff;
+ final boolean useLatestStates;
synchronized (BatteryExternalStatsWorker.this) {
updateFlags = mUpdateFlags;
reason = mCurrentReason;
uidsToRemove = mUidsToRemove.size() > 0 ? mUidsToRemove.toArray() : EmptyArray.INT;
+ onBattery = mOnBattery;
+ onBatteryScreenOff = mOnBatteryScreenOff;
+ useLatestStates = mUseLatestStates;
mUpdateFlags = 0;
mCurrentReason = null;
mUidsToRemove.clear();
mCurrentFuture = null;
+ mUseLatestStates = true;
}
synchronized (mWorkerLock) {
@@ -219,7 +286,8 @@
Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
}
try {
- updateExternalStatsLocked(reason, updateFlags);
+ updateExternalStatsLocked(reason, updateFlags, onBattery,
+ onBatteryScreenOff, useLatestStates);
} finally {
if (DEBUG) {
Slog.d(TAG, "end updateExternalStatsSync");
@@ -250,7 +318,8 @@
};
@GuardedBy("mWorkerLock")
- private void updateExternalStatsLocked(final String reason, int updateFlags) {
+ private void updateExternalStatsLocked(final String reason, int updateFlags,
+ boolean onBattery, boolean onBatteryScreenOff, boolean useLatestStates) {
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
@@ -306,7 +375,14 @@
reason, 0);
if ((updateFlags & UPDATE_CPU) != 0) {
- mStats.updateCpuTimeLocked();
+ if (useLatestStates) {
+ onBattery = mStats.isOnBatteryLocked();
+ onBatteryScreenOff = mStats.isOnBatteryScreenOffLocked();
+ }
+ mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff);
+ }
+
+ if ((updateFlags & UPDATE_ALL) != 0) {
mStats.updateKernelWakelocksLocked();
mStats.updateKernelMemoryBandwidthLocked();
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ea52782..9d1adb2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1057,7 +1057,7 @@
// to block such a low level service like BatteryService on external stats like WiFi.
mWorker.scheduleRunnable(() -> {
synchronized (mStats) {
- final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+ final boolean onBattery = BatteryStatsImpl.isOnBattery(plugType, status);
if (mStats.isOnBattery() == onBattery) {
// The battery state has not changed, so we don't need to sync external
// stats immediately.
diff --git a/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java b/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java
new file mode 100644
index 0000000..77713f5
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.view.RemoteAnimationAdapter;
+
+/**
+ * Registry to keep track of remote animations to be run for activity starts from a certain package.
+ *
+ * @see ActivityManagerService#registerRemoteAnimationForNextActivityStart
+ */
+class PendingRemoteAnimationRegistry {
+
+ private static final long TIMEOUT_MS = 3000;
+
+ private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
+ private final Handler mHandler;
+ private final ActivityManagerService mService;
+
+ PendingRemoteAnimationRegistry(ActivityManagerService service, Handler handler) {
+ mService = service;
+ mHandler = handler;
+ }
+
+ /**
+ * Adds a remote animation to be run for all activity starts originating from a certain package.
+ */
+ void addPendingAnimation(String packageName, RemoteAnimationAdapter adapter) {
+ mEntries.put(packageName, new Entry(packageName, adapter));
+ }
+
+ /**
+ * Overrides the activity options with a registered remote animation for a certain calling
+ * package if such a remote animation is registered.
+ */
+ ActivityOptions overrideOptionsIfNeeded(String callingPackage,
+ @Nullable ActivityOptions options) {
+ final Entry entry = mEntries.get(callingPackage);
+ if (entry == null) {
+ return options;
+ }
+ if (options == null) {
+ options = ActivityOptions.makeRemoteAnimation(entry.adapter);
+ } else {
+ options.setRemoteAnimationAdapter(entry.adapter);
+ }
+ mEntries.remove(callingPackage);
+ return options;
+ }
+
+ private class Entry {
+ final String packageName;
+ final RemoteAnimationAdapter adapter;
+
+ Entry(String packageName, RemoteAnimationAdapter adapter) {
+ this.packageName = packageName;
+ this.adapter = adapter;
+ mHandler.postDelayed(() -> {
+ synchronized (mService) {
+ final Entry entry = mEntries.get(packageName);
+ if (entry == this) {
+ mEntries.remove(packageName);
+ }
+ }
+ }, TIMEOUT_MS);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index fffe7dc..76e0d89 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -551,8 +551,6 @@
// Used to play ringtones outside system_server
private volatile IRingtonePlayer mRingtonePlayer;
- private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
-
// Request to override default use of A2DP for media.
private boolean mBluetoothA2dpEnabled;
private final Object mBluetoothA2dpEnabledLock = new Object();
@@ -571,8 +569,6 @@
AudioSystem.DEVICE_OUT_AUX_LINE;
int mFullVolumeDevices = 0;
- // TODO merge orientation and rotation
- private final boolean mMonitorOrientation;
private final boolean mMonitorRotation;
private boolean mDockAudioMediaEnabled = true;
@@ -788,13 +784,6 @@
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- // TODO merge orientation and rotation
- mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
- if (mMonitorOrientation) {
- Log.v(TAG, "monitoring device orientation");
- // initialize orientation in AudioSystem
- setOrientationForAudioSystem();
- }
mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
if (mMonitorRotation) {
RotationHelper.init(mContext, mAudioHandler);
@@ -963,10 +952,7 @@
// Restore ringer mode
setRingerModeInt(getRingerModeInternal(), false);
- // Reset device orientation (if monitored for this device)
- if (mMonitorOrientation) {
- setOrientationForAudioSystem();
- }
+ // Reset device rotation (if monitored for this device)
if (mMonitorRotation) {
RotationHelper.updateOrientation();
}
@@ -1042,14 +1028,16 @@
}
private void checkAllAliasStreamVolumes() {
- synchronized (VolumeStreamState.class) {
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- mStreamStates[streamType]
- .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
- // apply stream volume
- if (!mStreamStates[streamType].mIsMuted) {
- mStreamStates[streamType].applyAllVolumes();
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ mStreamStates[streamType]
+ .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
+ // apply stream volume
+ if (!mStreamStates[streamType].mIsMuted) {
+ mStreamStates[streamType].applyAllVolumes();
+ }
}
}
}
@@ -1155,13 +1143,16 @@
if (updateVolumes && mStreamStates != null) {
updateDefaultVolumes();
- mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
- caller);
-
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
- System.VOLUME_SETTINGS_INT[a11yStreamAlias];
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
- mStreamStates[a11yStreamAlias], caller);
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ mStreamStates[AudioSystem.STREAM_DTMF]
+ .setAllIndexes(mStreamStates[dtmfStreamAlias], caller);
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
+ System.VOLUME_SETTINGS_INT[a11yStreamAlias];
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
+ mStreamStates[a11yStreamAlias], caller);
+ }
+ }
if (sIndependentA11yVolume) {
// restore the a11y values from the settings
mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings();
@@ -4604,39 +4595,36 @@
* @param srcStream
* @param caller
*/
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
public void setAllIndexes(VolumeStreamState srcStream, String caller) {
if (mStreamType == srcStream.mStreamType) {
return;
}
- synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
- int srcStreamType = srcStream.getStreamType();
- // apply default device volume from source stream to all devices first in case
- // some devices are present in this stream state but not in source stream state
- int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
- index = rescaleIndex(index, srcStreamType, mStreamType);
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), index);
- }
- // Now apply actual volume for devices in source stream state
- SparseIntArray srcMap = srcStream.mIndexMap;
- for (int i = 0; i < srcMap.size(); i++) {
- int device = srcMap.keyAt(i);
- index = srcMap.valueAt(i);
- index = rescaleIndex(index, srcStreamType, mStreamType);
+ int srcStreamType = srcStream.getStreamType();
+ // apply default device volume from source stream to all devices first in case
+ // some devices are present in this stream state but not in source stream state
+ int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), index);
+ }
+ // Now apply actual volume for devices in source stream state
+ SparseIntArray srcMap = srcStream.mIndexMap;
+ for (int i = 0; i < srcMap.size(); i++) {
+ int device = srcMap.keyAt(i);
+ index = srcMap.valueAt(i);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
- setIndex(index, device, caller);
- }
- }
+ setIndex(index, device, caller);
}
}
- @GuardedBy("mSettingsLock")
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
public void setAllIndexesToMax() {
- synchronized (VolumeStreamState.class) {
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
- }
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
}
}
@@ -6192,24 +6180,15 @@
// Device orientation
//==========================================================================================
/**
- * Handles device configuration changes that may map to a change in the orientation
- * or orientation.
- * Monitoring orientation and rotation is optional, and is defined by the definition and value
- * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
+ * Handles device configuration changes that may map to a change in rotation.
+ * Monitoring rotation is optional, and is defined by the definition and value
+ * of the "ro.audio.monitorRotation" system property.
*/
private void handleConfigurationChanged(Context context) {
try {
- // reading new orientation "safely" (i.e. under try catch) in case anything
- // goes wrong when obtaining resources and configuration
+ // reading new configuration "safely" (i.e. under try catch) in case anything
+ // goes wrong.
Configuration config = context.getResources().getConfiguration();
- // TODO merge rotation and orientation
- if (mMonitorOrientation) {
- int newOrientation = config.orientation;
- if (newOrientation != mDeviceOrientation) {
- mDeviceOrientation = newOrientation;
- setOrientationForAudioSystem();
- }
- }
sendMsg(mAudioHandler,
MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
SENDMSG_REPLACE,
@@ -6224,15 +6203,17 @@
mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
- VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
- if (cameraSoundForced) {
- s.setAllIndexesToMax();
- mRingerModeAffectedStreams &=
- ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- } else {
- s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
- mRingerModeAffectedStreams |=
- (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ synchronized (VolumeStreamState.class) {
+ VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+ if (cameraSoundForced) {
+ s.setAllIndexesToMax();
+ mRingerModeAffectedStreams &=
+ ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
+ mRingerModeAffectedStreams |=
+ (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
}
// take new state into account for streams muted by ringer mode
setRingerModeInt(getRingerModeInternal(), false);
@@ -6261,30 +6242,6 @@
}
}
- //TODO move to an external "orientation helper" class
- private void setOrientationForAudioSystem() {
- switch (mDeviceOrientation) {
- case Configuration.ORIENTATION_LANDSCAPE:
- //Log.i(TAG, "orientation is landscape");
- AudioSystem.setParameters("orientation=landscape");
- break;
- case Configuration.ORIENTATION_PORTRAIT:
- //Log.i(TAG, "orientation is portrait");
- AudioSystem.setParameters("orientation=portrait");
- break;
- case Configuration.ORIENTATION_SQUARE:
- //Log.i(TAG, "orientation is square");
- AudioSystem.setParameters("orientation=square");
- break;
- case Configuration.ORIENTATION_UNDEFINED:
- //Log.i(TAG, "orientation is undefined");
- AudioSystem.setParameters("orientation=undefined");
- break;
- default:
- Log.e(TAG, "Unknown orientation");
- }
- }
-
// Handles request to override default use of A2DP for media.
// Must be called synchronized on mConnectedDevices
public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b5f94b1..3da3551 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -915,7 +915,7 @@
notifyLockoutResetMonitors();
}
- private class FingerprintServiceLockoutResetMonitor {
+ private class FingerprintServiceLockoutResetMonitor implements IBinder.DeathRecipient {
private static final long WAKELOCK_TIMEOUT_MS = 2000;
private final IFingerprintServiceLockoutResetCallback mCallback;
@@ -926,6 +926,11 @@
mCallback = callback;
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"lockout reset callback");
+ try {
+ mCallback.asBinder().linkToDeath(FingerprintServiceLockoutResetMonitor.this, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath", e);
+ }
}
public void sendLockoutReset() {
@@ -959,6 +964,12 @@
removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
}
};
+
+ @Override
+ public void binderDied() {
+ Slog.e(TAG, "Lockout reset callback binder died");
+ mHandler.post(mRemoveCallbackRunnable);
+ }
}
private IBiometricsFingerprintClientCallback mDaemonCallback =
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index c9c9329..c4f1f3d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -19,9 +19,6 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
-
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.app.admin.DevicePolicyManager;
@@ -29,10 +26,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Binder;
-import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -40,7 +36,7 @@
import android.util.Slog;
import android.util.SparseIntArray;
-import java.util.ArrayList;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
/**
* Keeps track of requests for strong authentication.
@@ -58,7 +54,7 @@
private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
"LockSettingsStrongAuth.timeoutForUser";
- private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
+ private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
@@ -82,12 +78,7 @@
}
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
- return;
- }
- }
- mStrongAuthTrackers.add(tracker);
+ mTrackers.register(tracker);
for (int i = 0; i < mStrongAuthForUser.size(); i++) {
int key = mStrongAuthForUser.keyAt(i);
@@ -101,12 +92,7 @@
}
private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
- mStrongAuthTrackers.remove(i);
- return;
- }
- }
+ mTrackers.unregister(tracker);
}
private void handleRequireStrongAuth(int strongAuthReason, int userId) {
@@ -157,16 +143,19 @@
}
private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- try {
- mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId);
- } catch (DeadObjectException e) {
- Slog.d(TAG, "Removing dead StrongAuthTracker.");
- mStrongAuthTrackers.remove(i);
+ int i = mTrackers.beginBroadcast();
+ try {
+ while (i > 0) {
i--;
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ try {
+ mTrackers.getBroadcastItem(i).onStrongAuthRequiredChanged(
+ strongAuthReason, userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ }
}
+ } finally {
+ mTrackers.finishBroadcast();
}
}
@@ -243,4 +232,5 @@
}
}
};
+
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
new file mode 100644
index 0000000..bb487fb
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 152c910..23a66ba 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -170,11 +170,13 @@
certXml = CertXml.parse(recoveryServiceCertFile);
} catch (CertParsingException e) {
// TODO: Do not use raw key bytes anymore once the other components are updated
- Log.d(TAG, "Failed to parse the cert file", e);
+ Log.d(TAG, "Failed to parse the input as a cert file: " + HexDump.toHexString(
+ recoveryServiceCertFile));
PublicKey publicKey = parseEcPublicKey(recoveryServiceCertFile);
if (mDatabase.setRecoveryServicePublicKey(userId, uid, publicKey) > 0) {
mDatabase.setShouldCreateSnapshot(userId, uid, true);
}
+ Log.d(TAG, "Successfully set the input as the raw public key");
return;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f346629..e2b2d46 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -145,6 +145,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -2759,6 +2760,13 @@
return;
}
+ // Fourth check: is caller a testing app on a debug build?
+ final boolean enableDebug = Build.IS_USERDEBUG || Build.IS_ENG;
+ if (enableDebug && callingPackage
+ .equals(SystemProperties.get("fw.sub_plan_owner." + subId, null))) {
+ return;
+ }
+
// Final check: does the caller hold a permission?
mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 44b83d8..0a87097 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1178,7 +1178,7 @@
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
mContext.getResources().getString(R.string.global_action_settings));
return new Notification.Builder(mContext, SystemNotificationChannels.SYSTEM_CHANGES)
- .setSmallIcon(R.drawable.ic_settings)
+ .setSmallIcon(R.drawable.ic_settings_24dp)
.setContentTitle(mContext.getResources().getString(
R.string.zen_upgrade_notification_title))
.setContentText(mContext.getResources().getString(
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a0577b1..0eeaf66 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1486,6 +1486,23 @@
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
+ /** @return if any user has the given restriction. */
+ @Override
+ public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+ if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+ return false;
+ }
+ final List<UserInfo> users = getUsers(/* excludeDying= */ true);
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+ Bundle restrictions = getEffectiveUserRestrictions(userId);
+ if (restrictions != null && restrictions.getBoolean(restrictionKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* @hide
*
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 23185d7..41570c4 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -33,6 +33,7 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Log;
@@ -581,6 +582,15 @@
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, "0");
}
break;
+ case UserManager.DISALLOW_CONFIG_LOCATION:
+ // When DISALLOW_CONFIG_LOCATION is set on any user, we undo the global
+ // kill switch.
+ if (newValue) {
+ android.provider.Settings.Global.putString(
+ context.getContentResolver(),
+ Global.LOCATION_GLOBAL_KILL_SWITCH, "0");
+ }
+ break;
}
} finally {
Binder.restoreCallingIdentity(id);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ce3f512..8155656 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1766,6 +1766,9 @@
layer += Z_BOOST_BASE;
}
leash.setLayer(layer);
+
+ final DisplayContent dc = getDisplayContent();
+ dc.assignStackOrdering(t);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f421bf4..2d32c81 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3524,39 +3524,47 @@
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
+ assignStackOrdering(t);
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ s.assignChildLayers(t);
+ }
+ }
+
+ void assignStackOrdering(SurfaceControl.Transaction t) {
final int HOME_STACK_STATE = 0;
final int NORMAL_STACK_STATE = 1;
final int ALWAYS_ON_TOP_STATE = 2;
int layer = 0;
+ int layerForAnimationLayer = 0;
+
for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
for (int i = 0; i < mChildren.size(); i++) {
final TaskStack s = mChildren.get(i);
- if (state == HOME_STACK_STATE && s.isActivityTypeHome()) {
- s.assignLayer(t, layer++);
- } else if (state == NORMAL_STACK_STATE && !s.isActivityTypeHome()
- && !s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
- if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
- t.setLayer(mSplitScreenDividerAnchor, layer++);
- }
- } else if (state == ALWAYS_ON_TOP_STATE && s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
+ if (state == HOME_STACK_STATE && !s.isActivityTypeHome()) {
+ continue;
+ } else if (state == NORMAL_STACK_STATE && (s.isActivityTypeHome()
+ || s.isAlwaysOnTop())) {
+ continue;
+ } else if (state == ALWAYS_ON_TOP_STATE && !s.isAlwaysOnTop()) {
+ continue;
+ }
+ s.assignLayer(t, layer++);
+ if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
+ t.setLayer(mSplitScreenDividerAnchor, layer++);
+ }
+ if (s.isSelfOrChildAnimating()) {
+ // Ensure the animation layer ends up above the
+ // highest animating stack and no higher.
+ layerForAnimationLayer = layer++;
}
}
- // The appropriate place for App-Transitions to occur is right
- // above all other animations but still below things in the Picture-and-Picture
- // windowing mode.
- if (state == NORMAL_STACK_STATE && mAppAnimationLayer != null) {
- t.setLayer(mAppAnimationLayer, layer++);
- }
}
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- s.assignChildLayers(t);
+ if (mAppAnimationLayer != null) {
+ t.setLayer(mAppAnimationLayer, layerForAnimationLayer);
}
-
}
@Override
@@ -3854,4 +3862,8 @@
super.prepareSurfaces();
}
+
+ void assignStackOrdering(SurfaceControl.Transaction t) {
+ mTaskStackContainers.assignStackOrdering(t);
+ }
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 97a2954..e4edeb87 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -24,15 +24,15 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.WindowConfiguration;
-import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.view.IRecentsAnimationController;
@@ -41,6 +41,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -99,17 +100,13 @@
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
final Task task = adapter.mTask;
if (task.mTaskId == taskId) {
- // TODO: Save this screenshot as the task snapshot?
- final Rect taskFrame = new Rect();
- task.getBounds(taskFrame);
- final GraphicBuffer buffer = SurfaceControl.captureLayers(
- task.getSurfaceControl().getHandle(), taskFrame, 1f);
- final AppWindowToken topChild = task.getTopChild();
- final WindowState mainWindow = topChild.findMainWindow();
- return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
- mainWindow.mContentInsets,
- ActivityManager.isLowRamDeviceStatic() /* reduced */,
- 1.0f /* scale */);
+ final TaskSnapshotController snapshotController =
+ mService.mTaskSnapshotController;
+ final ArraySet<Task> tasks = Sets.newArraySet(task);
+ snapshotController.snapshotTasks(tasks);
+ snapshotController.addSkipClosingAppSnapshotTasks(tasks);
+ return snapshotController.getSnapshot(taskId, 0 /* userId */,
+ false /* restoreFromDisk */, false /* reducedResolution */);
}
}
return null;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index a7a2b53..3d7b32c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -92,6 +92,7 @@
private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
Environment::getDataSystemCeDirectory);
private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
+ private final ArraySet<Task> mSkipClosingAppSnapshotTasks = new ArraySet<>();
private final ArraySet<Task> mTmpTasks = new ArraySet<>();
private final Handler mHandler = new Handler();
@@ -149,10 +150,20 @@
// either closing or hidden.
getClosingTasks(closingApps, mTmpTasks);
snapshotTasks(mTmpTasks);
-
+ mSkipClosingAppSnapshotTasks.clear();
}
- private void snapshotTasks(ArraySet<Task> tasks) {
+ /**
+ * Adds the given {@param tasks} to the list of tasks which should not have their snapshots
+ * taken upon the next processing of the set of closing apps. The caller is responsible for
+ * calling {@link #snapshotTasks} to ensure that the task has an up-to-date snapshot.
+ */
+ @VisibleForTesting
+ void addSkipClosingAppSnapshotTasks(ArraySet<Task> tasks) {
+ mSkipClosingAppSnapshotTasks.addAll(tasks);
+ }
+
+ void snapshotTasks(ArraySet<Task> tasks) {
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task task = tasks.valueAt(i);
final int mode = getSnapshotMode(task);
@@ -295,7 +306,7 @@
// If the task of the app is not visible anymore, it means no other app in that task
// is opening. Thus, the task is closing.
- if (task != null && !task.isVisible()) {
+ if (task != null && !task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) {
outClosingTasks.add(task);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index fa4474b..93e9137 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1129,7 +1129,7 @@
scheduleAnimation();
}
- private void reassignLayer(Transaction t) {
+ void reassignLayer(Transaction t) {
final WindowContainer parent = getParent();
if (parent != null) {
parent.assignChildLayers(t);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 72f95fb..0b03281 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -41,6 +41,7 @@
"com_android_server_tv_TvUinputBridge.cpp",
"com_android_server_tv_TvInputHal.cpp",
"com_android_server_vr_VrManagerService.cpp",
+ "com_android_server_UsbAlsaJackDetector.cpp",
"com_android_server_UsbDeviceManager.cpp",
"com_android_server_UsbDescriptorParser.cpp",
"com_android_server_UsbMidiDevice.cpp",
@@ -97,6 +98,7 @@
"libgui",
"libusbhost",
"libsuspend",
+ "libtinyalsa",
"libEGL",
"libGLESv2",
"libnetutils",
diff --git a/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
new file mode 100644
index 0000000..e9d4482
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UsbAlsaJackDetectorJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#define DRIVER_NAME "/dev/usb_accessory"
+
+#define USB_IN_JACK_NAME "USB in Jack"
+#define USB_OUT_JACK_NAME "USB out Jack"
+
+namespace android
+{
+
+static jboolean is_jack_connected(jint card, const char* control) {
+ struct mixer* card_mixer = mixer_open(card);
+ if (card_mixer == NULL) {
+ return true;
+ }
+ struct mixer_ctl* ctl = mixer_get_ctl_by_name(card_mixer, control);
+ if (!ctl) {
+ return true;
+ }
+ mixer_ctl_update(ctl);
+ int val = mixer_ctl_get_value(ctl, 0);
+ ALOGI("JACK %s - value %d\n", control, val);
+ mixer_close(card_mixer);
+
+ return val != 0;
+}
+
+static jboolean android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ struct mixer* card_mixer = mixer_open(card);
+ if (card_mixer == NULL) {
+ return false;
+ }
+
+ jboolean has_jack = false;
+ if ((mixer_get_ctl_by_name(card_mixer, USB_IN_JACK_NAME) != NULL) ||
+ (mixer_get_ctl_by_name(card_mixer, USB_OUT_JACK_NAME) != NULL)) {
+ has_jack = true;
+ }
+ mixer_close(card_mixer);
+ return has_jack;
+}
+
+
+static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ return is_jack_connected(card, USB_IN_JACK_NAME);
+}
+
+
+static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ return is_jack_connected(card, USB_OUT_JACK_NAME);
+}
+
+static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env,
+ jobject thiz,
+ jint card) {
+ jclass jdclass = env->GetObjectClass(thiz);
+ jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z");
+ if (method_jackDetectCallback == NULL) {
+ ALOGE("Can't find jackDetectCallback");
+ return;
+ }
+
+ struct mixer* m = mixer_open(card);
+ if (!m) {
+ ALOGE("Jack detect unable to open mixer\n");
+ return;
+ }
+ mixer_subscribe_events(m, 1);
+ do {
+
+ // Wait for a mixer event. Retry if interrupted, exit on error.
+ int retval;
+ do {
+ retval = mixer_wait_event(m, -1);
+ } while (retval == -EINTR);
+ if (retval < 0) {
+ break;
+ }
+ mixer_consume_event(m);
+ } while (env->CallBooleanMethod(thiz, method_jackDetectCallback));
+
+ mixer_close(m);
+ return;
+}
+
+static const JNINativeMethod method_table[] = {
+ { "nativeHasJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_hasJackDetect },
+ { "nativeInputJackConnected", "(I)Z",
+ (void*)android_server_UsbAlsaJackDetector_inputJackConnected },
+ { "nativeOutputJackConnected", "(I)Z",
+ (void*)android_server_UsbAlsaJackDetector_outputJackConnected },
+ { "nativeJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_jackDetect },
+};
+
+int register_android_server_UsbAlsaJackDetector(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/usb/UsbAlsaJackDetector");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/usb/UsbAlsaJackDetector");
+ return -1;
+ }
+
+ if (!jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaJackDetector",
+ method_table, NELEM(method_table))) {
+ ALOGE("Can't register UsbAlsaJackDetector native methods");
+ return -1;
+ }
+
+ return 0;
+}
+
+}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bf2a637..0ebef37 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -34,6 +34,7 @@
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
+int register_android_server_UsbAlsaJackDetector(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
@@ -82,6 +83,7 @@
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbMidiDevice(env);
+ register_android_server_UsbAlsaJackDetector(env);
register_android_server_UsbHostManager(env);
register_android_server_vr_VrManagerService(env);
register_android_server_VibratorService(env);
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 07262e1..23fe0ff 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -34,7 +34,6 @@
import android.annotation.NonNull;
import android.content.Context;
-import android.os.Handler;
import android.os.Message;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -49,9 +48,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.concurrent.CompletableFuture;
import java.util.function.IntConsumer;
-import java.util.function.Supplier;
/**
@@ -283,6 +280,19 @@
verify(mMgh.getNext(), times(2)).onMotionEvent(any(), any(), anyInt());
}
+ @Test
+ public void testTripleTapAndHold_zoomsImmediately() {
+ assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS);
+ assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
+ }
+
+ private void assertZoomsImmediatelyOnSwipeFrom(int state) {
+ goFromStateIdleTo(state);
+ swipeAndHold();
+ assertIn(STATE_DRAGGING_TMP);
+ returnToNormalFrom(STATE_DRAGGING_TMP);
+ }
+
private void assertTransition(int fromState, Runnable transitionAction, int toState) {
goFromStateIdleTo(fromState);
transitionAction.run();
@@ -339,11 +349,13 @@
check(tapCount() == 2, state);
} break;
case STATE_DRAGGING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
} break;
case STATE_DRAGGING_TMP: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
@@ -353,11 +365,13 @@
check(!isZoomed(), state);
} break;
case STATE_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(!mMgh.mPanningScalingState.mScaling, state);
} break;
case STATE_SCALING_AND_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(mMgh.mPanningScalingState.mScaling, state);
diff --git a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
new file mode 100644
index 0000000..2baf995
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import android.view.RemoteAnimationAdapter;
+
+import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest PendingRemoteAnimationRegistryTest
+ */
+@SmallTest
+@Presubmit
+@FlakyTest
+@RunWith(AndroidJUnit4.class)
+public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase {
+
+ @Mock RemoteAnimationAdapter mAdapter;
+ private PendingRemoteAnimationRegistry mRegistry;
+ private final OffsettableClock mClock = new OffsettableClock.Stopped();
+ private TestHandler mHandler;
+ private ActivityManagerService mService;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ mService = createActivityManagerService();
+ mService.mHandlerThread.getThreadHandler().runWithScissors(() -> {
+ mHandler = new TestHandler(null, mClock);
+ }, 0);
+ mRegistry = new PendingRemoteAnimationRegistry(mService, mHandler);
+ }
+
+ @Test
+ public void testOverrideActivityOptions() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts = mRegistry.overrideOptionsIfNeeded("com.android.test", opts);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+
+ @Test
+ public void testOverrideActivityOptions_null() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
+ assertNotNull(opts);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+
+ @Test
+ public void testTimeout() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(5000);
+ mHandler.timeAdvance();
+ assertNull(mRegistry.overrideOptionsIfNeeded("com.android.test", null));
+ }
+
+ @Test
+ public void testTimeout_overridenEntry() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(2500);
+ mHandler.timeAdvance();
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(1000);
+ mHandler.timeAdvance();
+ final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
new file mode 100644
index 0000000..bb487fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 6e1808b..28b54ef 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -323,6 +323,7 @@
private void turnBatteryOn() throws Exception {
executeCommand("cmd battery unplug");
+ executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_NOT_CHARGING);
assertBatteryOn();
}
@@ -336,6 +337,7 @@
private void turnBatteryOff() throws Exception {
executeCommand("cmd battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+ executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_CHARGING);
}
private static void batteryReset() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
index 029d9f1..1222b59 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
@@ -16,10 +16,11 @@
package com.android.server.testutils;
-import static android.util.ExceptionUtils.getRootCause;
+import static android.util.ExceptionUtils.appendCause;
import static android.util.ExceptionUtils.propagate;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -60,7 +61,7 @@
}
public TestHandler(Callback callback, LongSupplier clock) {
- super(callback);
+ super(Looper.getMainLooper(), callback);
mClock = clock;
}
@@ -132,7 +133,7 @@
} catch (Throwable t) {
// Append stack trace of this message being posted as a cause for a helpful
// test error message
- throw propagate(getRootCause(t).initCause(msg.postPoint));
+ throw propagate(appendCause(t, msg.postPoint));
} finally {
msg.message.recycle();
}
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 78b6077..cbbdca6 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -308,6 +308,7 @@
private void reportEvent(AppStandbyController controller, int eventType,
long elapsedTime) {
// Back to ACTIVE on event
+ mInjector.mElapsedRealtime = elapsedTime;
UsageEvents.Event ev = new UsageEvents.Event();
ev.mPackage = PACKAGE_1;
ev.mEventType = eventType;
@@ -487,6 +488,89 @@
}
@Test
+ public void testCascadingTimeouts() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
+ REASON_PREDICTED, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
+ assertBucket(STANDBY_BUCKET_FREQUENT);
+ }
+
+ @Test
+ public void testOverlappingTimeouts() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Overlapping USER_INTERACTION before previous one times out
+ reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Still in ACTIVE after first USER_INTERACTION times out
+ mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Both timed out, so NOTIFICATION_SEEN timeout should be effective
+ mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_RARE);
+ }
+
+ @Test
+ public void testPredictionNotOverridden() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
+ reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Falls back to WORKING_SET
+ mInjector.mElapsedRealtime += 5000;
+ mController.checkIdleStates(USER_ID);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ // Predict to ACTIVE
+ mInjector.mElapsedRealtime += 1000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // CheckIdleStates should not change the prediction
+ mInjector.mElapsedRealtime += 1000;
+ mController.checkIdleStates(USER_ID);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+ }
+
+ @Test
public void testAddActiveDeviceAdmin() {
assertActiveAdmins(USER_ID, (String[]) null);
assertActiveAdmins(USER_ID2, (String[]) null);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 920796e..5650050 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -29,6 +29,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
+import com.google.android.collect.Sets;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,6 +75,21 @@
}
@Test
+ public void testGetClosingApps_skipClosingAppsSnapshotTasks() throws Exception {
+ final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
+ "closingWindow");
+ closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+ true /* performLayout */, false /* isVoiceInteraction */);
+ final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
+ closingApps.add(closingWindow.mAppToken);
+ final ArraySet<Task> closingTasks = new ArraySet<>();
+ sWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
+ Sets.newArraySet(closingWindow.mAppToken.getTask()));
+ sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ assertEquals(0, closingTasks.size());
+ }
+
+ @Test
public void testGetSnapshotMode() throws Exception {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index b654a66..f26c2ae 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -23,6 +23,7 @@
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import android.app.usage.UsageStatsManager;
import android.os.SystemClock;
@@ -87,7 +88,9 @@
// The last time a job was run for this app
private static final String ATTR_LAST_RUN_JOB_TIME = "lastJobRunTime";
// The time when the forced active state can be overridden.
- private static final String ATTR_BUCKET_TIMEOUT_TIME = "bucketTimeoutTime";
+ private static final String ATTR_BUCKET_ACTIVE_TIMEOUT_TIME = "activeTimeoutTime";
+ // The time when the forced working_set state can be overridden.
+ private static final String ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME = "workingSetTimeoutTime";
// device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
@@ -117,11 +120,15 @@
int lastInformedBucket;
// The last time a job was run for this app, using elapsed timebase
long lastJobRunTime;
- // When should the bucket state timeout, in elapsed timebase, if greater than
+ // When should the bucket active state timeout, in elapsed timebase, if greater than
// lastUsedElapsedTime.
// This is used to keep the app in a high bucket regardless of other timeouts and
// predictions.
- long bucketTimeoutTime;
+ long bucketActiveTimeoutTime;
+ // If there's a forced working_set state, this is when it times out. This can be sitting
+ // under any active state timeout, so that it becomes applicable after the active state
+ // timeout expires.
+ long bucketWorkingSetTimeoutTime;
}
AppIdleHistory(File storageDir, long elapsedRealtime) {
@@ -208,11 +215,28 @@
* @param packageName name of the app being updated, for logging purposes
* @param newBucket the bucket to set the app to
* @param elapsedRealtime mark as used time if non-zero
- * @param timeout set the timeout of the specified bucket, if non-zero
+ * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
+ * with bucket values of ACTIVE and WORKING_SET.
* @return
*/
public AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName,
int newBucket, long elapsedRealtime, long timeout) {
+ // Set the timeout if applicable
+ if (timeout > elapsedRealtime) {
+ // Convert to elapsed timebase
+ final long timeoutTime = mElapsedDuration + (timeout - mElapsedSnapshot);
+ if (newBucket == STANDBY_BUCKET_ACTIVE) {
+ appUsageHistory.bucketActiveTimeoutTime = Math.max(timeoutTime,
+ appUsageHistory.bucketActiveTimeoutTime);
+ } else if (newBucket == STANDBY_BUCKET_WORKING_SET) {
+ appUsageHistory.bucketWorkingSetTimeoutTime = Math.max(timeoutTime,
+ appUsageHistory.bucketWorkingSetTimeoutTime);
+ } else {
+ throw new IllegalArgumentException("Cannot set a timeout on bucket=" +
+ newBucket);
+ }
+ }
+
if (elapsedRealtime != 0) {
appUsageHistory.lastUsedElapsedTime = mElapsedDuration
+ (elapsedRealtime - mElapsedSnapshot);
@@ -226,12 +250,6 @@
.currentBucket
+ ", reason=" + appUsageHistory.bucketingReason);
}
- if (timeout > elapsedRealtime) {
- // Convert to elapsed timebase
- appUsageHistory.bucketTimeoutTime =
- Math.max(appUsageHistory.bucketTimeoutTime,
- mElapsedDuration + (timeout - mElapsedSnapshot));
- }
}
appUsageHistory.bucketingReason = REASON_USAGE;
@@ -247,7 +265,8 @@
* @param userId
* @param newBucket the bucket to set the app to
* @param elapsedRealtime mark as used time if non-zero
- * @param timeout set the timeout of the specified bucket, if non-zero
+ * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
+ * with bucket values of ACTIVE and WORKING_SET.
* @return
*/
public AppUsageHistory reportUsage(String packageName, int userId, int newBucket,
@@ -504,8 +523,10 @@
parser.getAttributeValue(null, ATTR_BUCKETING_REASON);
appUsageHistory.lastJobRunTime = getLongValue(parser,
ATTR_LAST_RUN_JOB_TIME, Long.MIN_VALUE);
- appUsageHistory.bucketTimeoutTime = getLongValue(parser,
- ATTR_BUCKET_TIMEOUT_TIME, 0L);
+ appUsageHistory.bucketActiveTimeoutTime = getLongValue(parser,
+ ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, 0L);
+ appUsageHistory.bucketWorkingSetTimeoutTime = getLongValue(parser,
+ ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, 0L);
if (appUsageHistory.bucketingReason == null) {
appUsageHistory.bucketingReason = REASON_DEFAULT;
}
@@ -557,9 +578,13 @@
xml.attribute(null, ATTR_CURRENT_BUCKET,
Integer.toString(history.currentBucket));
xml.attribute(null, ATTR_BUCKETING_REASON, history.bucketingReason);
- if (history.bucketTimeoutTime > 0) {
- xml.attribute(null, ATTR_BUCKET_TIMEOUT_TIME, Long.toString(history
- .bucketTimeoutTime));
+ if (history.bucketActiveTimeoutTime > 0) {
+ xml.attribute(null, ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, Long.toString(history
+ .bucketActiveTimeoutTime));
+ }
+ if (history.bucketWorkingSetTimeoutTime > 0) {
+ xml.attribute(null, ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, Long.toString(history
+ .bucketWorkingSetTimeoutTime));
}
if (history.lastJobRunTime != Long.MIN_VALUE) {
xml.attribute(null, ATTR_LAST_RUN_JOB_TIME, Long.toString(history
@@ -593,14 +618,19 @@
continue;
}
idpw.print("package=" + packageName);
+ idpw.print(" userId=" + userId);
idpw.print(" lastUsedElapsed=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
idpw.print(" lastUsedScreenOn=");
TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
idpw.print(" lastPredictedTime=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
- idpw.print(" bucketTimeoutTime=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketTimeoutTime, idpw);
+ idpw.print(" bucketActiveTimeoutTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketActiveTimeoutTime,
+ idpw);
+ idpw.print(" bucketWorkingSetTimeoutTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketWorkingSetTimeoutTime,
+ idpw);
idpw.print(" lastJobRunTime=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 32db752..c31809e 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,6 +30,7 @@
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.usage.UsageStatsManager.StandbyBuckets;
@@ -171,6 +172,8 @@
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
+ /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
+ static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
long mCheckIdleIntervalMillis;
long mAppIdleParoleIntervalMillis;
@@ -322,7 +325,7 @@
// Get sync adapters for the authority
String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
authority, userId);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mInjector.elapsedRealtime();
for (String packageName: packages) {
// Only force the sync adapters to active if the provider is not in the same package and
// the sync adapter is a system package.
@@ -460,53 +463,8 @@
for (int p = 0; p < packageCount; p++) {
final PackageInfo pi = packages.get(p);
final String packageName = pi.packageName;
- final boolean isSpecial = isAppSpecial(packageName,
- UserHandle.getAppId(pi.applicationInfo.uid),
- userId);
- if (DEBUG) {
- Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
- isSpecial);
- }
- if (isSpecial) {
- synchronized (mAppIdleLock) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
- }
- maybeInformListeners(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, false);
- } else {
- synchronized (mAppIdleLock) {
- AppIdleHistory.AppUsageHistory app =
- mAppIdleHistory.getAppUsageHistory(packageName,
- userId, elapsedRealtime);
- // If the bucket was forced by the developer or the app is within the
- // temporary active period, leave it alone.
- if (REASON_FORCED.equals(app.bucketingReason)
- || !hasBucketTimeoutPassed(app, elapsedRealtime)) {
- continue;
- }
- boolean predictionLate = false;
- // If the bucket was moved up due to usage, let the timeouts apply.
- if (REASON_DEFAULT.equals(app.bucketingReason)
- || REASON_USAGE.equals(app.bucketingReason)
- || REASON_TIMEOUT.equals(app.bucketingReason)
- || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
- int oldBucket = app.currentBucket;
- int newBucket = getBucketForLocked(packageName, userId,
- elapsedRealtime);
- if (DEBUG) {
- Slog.d(TAG, " Old bucket=" + oldBucket
- + ", newBucket=" + newBucket);
- }
- if (oldBucket < newBucket || predictionLate) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, REASON_TIMEOUT);
- maybeInformListeners(packageName, userId, elapsedRealtime,
- newBucket, false);
- }
- }
- }
- }
+ checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
+ elapsedRealtime);
}
}
if (DEBUG) {
@@ -516,6 +474,90 @@
return true;
}
+ /** Check if we need to update the standby state of a specific app. */
+ private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
+ int uid, long elapsedRealtime) {
+ if (uid <= 0) {
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Not a valid package for this user, nothing to do
+ // TODO: Remove any history of removed packages
+ return;
+ }
+ }
+ final boolean isSpecial = isAppSpecial(packageName,
+ UserHandle.getAppId(uid),
+ userId);
+ if (DEBUG) {
+ Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
+ isSpecial);
+ }
+ if (isSpecial) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
+ }
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, false);
+ } else {
+ synchronized (mAppIdleLock) {
+ final AppIdleHistory.AppUsageHistory app =
+ mAppIdleHistory.getAppUsageHistory(packageName,
+ userId, elapsedRealtime);
+ String reason = app.bucketingReason;
+
+ // If the bucket was forced by the user/developer, leave it alone.
+ // A usage event will be the only way to bring it out of this forced state
+ if (REASON_FORCED.equals(app.bucketingReason)) {
+ return;
+ }
+ final int oldBucket = app.currentBucket;
+ int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
+ boolean predictionLate = false;
+ // Compute age-based bucket
+ if (REASON_DEFAULT.equals(app.bucketingReason)
+ || REASON_USAGE.equals(app.bucketingReason)
+ || REASON_TIMEOUT.equals(app.bucketingReason)
+ || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
+ newBucket = getBucketForLocked(packageName, userId,
+ elapsedRealtime);
+ if (DEBUG) {
+ Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
+ }
+ reason = REASON_TIMEOUT;
+ }
+ // Check if the app is within one of the timeouts for forced bucket elevation
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ if (newBucket >= STANDBY_BUCKET_ACTIVE
+ && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_ACTIVE;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
+ }
+ } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
+ && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_WORKING_SET;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, " Old bucket=" + oldBucket
+ + ", newBucket=" + newBucket);
+ }
+ if (oldBucket < newBucket || predictionLate) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId,
+ elapsedRealtime, newBucket, reason);
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ newBucket, false);
+ }
+ }
+ }
+ }
+
private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
return app.bucketingReason != null
&& app.bucketingReason.startsWith(REASON_PREDICTED)
@@ -526,7 +568,9 @@
private boolean hasBucketTimeoutPassed(AppIdleHistory.AppUsageHistory app,
long elapsedRealtime) {
- return app.bucketTimeoutTime < mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ return app.bucketActiveTimeoutTime < elapsedTimeAdjusted
+ && app.bucketWorkingSetTimeoutTime < elapsedTimeAdjusted;
}
private void maybeInformListeners(String packageName, int userId,
@@ -631,16 +675,22 @@
event.mPackage, userId, elapsedRealtime);
final int prevBucket = appHistory.currentBucket;
final String prevBucketReason = appHistory.bucketingReason;
+ final long nextCheckTime;
if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
+ // Mild usage elevates to WORKING_SET but doesn't change usage time.
mAppIdleHistory.reportUsage(appHistory, event.mPackage,
STANDBY_BUCKET_WORKING_SET,
- elapsedRealtime, elapsedRealtime + mNotificationSeenTimeoutMillis);
+ 0, elapsedRealtime + mNotificationSeenTimeoutMillis);
+ nextCheckTime = mNotificationSeenTimeoutMillis;
} else {
- mAppIdleHistory.reportUsage(event.mPackage, userId,
+ mAppIdleHistory.reportUsage(appHistory, event.mPackage,
STANDBY_BUCKET_ACTIVE,
elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
+ nextCheckTime = mStrongUsageTimeoutMillis;
}
-
+ mHandler.sendMessageDelayed(mHandler.obtainMessage
+ (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage),
+ nextCheckTime);
final boolean userStartedInteracting =
appHistory.currentBucket == STANDBY_BUCKET_ACTIVE &&
prevBucket != appHistory.currentBucket &&
@@ -932,9 +982,24 @@
// If the bucket is required to stay in a higher state for a specified duration, don't
// override unless the duration has passed
- if (predicted && app.currentBucket < newBucket
- && !hasBucketTimeoutPassed(app, elapsedRealtime)) {
- return;
+ if (predicted) {
+ // Check if the app is within one of the timeouts for forced bucket elevation
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ if (newBucket > STANDBY_BUCKET_ACTIVE
+ && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_ACTIVE;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
+ }
+ } else if (newBucket > STANDBY_BUCKET_WORKING_SET
+ && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_WORKING_SET;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
+ }
+ }
}
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
@@ -1347,6 +1412,10 @@
+ ", Charging state:" + mCharging);
informParoleStateChanged();
break;
+ case MSG_CHECK_PACKAGE_IDLE_STATE:
+ checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
+ mInjector.elapsedRealtime());
+ break;
default:
super.handleMessage(msg);
break;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 7480e56..9d4db00 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -17,9 +17,14 @@
package com.android.server.usb;
import android.annotation.NonNull;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.os.RemoteException;
import android.service.usb.UsbAlsaDeviceProto;
+import android.util.Slog;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.server.audio.AudioService;
/**
* Represents the ALSA specification, and attributes of an ALSA device.
@@ -30,25 +35,31 @@
private final int mCardNum;
private final int mDeviceNum;
- private final boolean mHasPlayback;
- private final boolean mHasCapture;
+ private final String mDeviceAddress;
+ private final boolean mHasOutput;
+ private final boolean mHasInput;
private final boolean mIsInputHeadset;
private final boolean mIsOutputHeadset;
- private final String mDeviceAddress;
+ private boolean mSelected = false;
+ private int mOutputState;
+ private int mInputState;
+ private UsbAlsaJackDetector mJackDetector;
+ private IAudioService mAudioService;
private String mDeviceName = "";
private String mDeviceDescription = "";
- public UsbAlsaDevice(int card, int device, String deviceAddress,
- boolean hasPlayback, boolean hasCapture,
+ public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
+ boolean hasOutput, boolean hasInput,
boolean isInputHeadset, boolean isOutputHeadset) {
+ mAudioService = audioService;
mCardNum = card;
mDeviceNum = device;
mDeviceAddress = deviceAddress;
- mHasPlayback = hasPlayback;
- mHasCapture = hasCapture;
+ mHasOutput = hasOutput;
+ mHasInput = hasInput;
mIsInputHeadset = isInputHeadset;
mIsOutputHeadset = isOutputHeadset;
}
@@ -75,71 +86,187 @@
}
/**
- * @returns true if the device supports playback.
+ * @returns the ALSA card/device address string.
*/
- public boolean hasPlayback() {
- return mHasPlayback;
+ public String getAlsaCardDeviceString() {
+ if (mCardNum < 0 || mDeviceNum < 0) {
+ Slog.e(TAG, "Invalid alsa card or device alsaCard: " + mCardNum
+ + " alsaDevice: " + mDeviceNum);
+ return null;
+ }
+ return AudioService.makeAlsaAddressString(mCardNum, mDeviceNum);
}
/**
- * @returns true if the device supports capture (recording).
+ * @returns true if the device supports output.
*/
- public boolean hasCapture() {
- return mHasCapture;
+ public boolean hasOutput() {
+ return mHasOutput;
}
/**
- * @returns true if the device is a headset for purposes of capture.
+ * @returns true if the device supports input (recording).
+ */
+ public boolean hasInput() {
+ return mHasInput;
+ }
+
+ /**
+ * @returns true if the device is a headset for purposes of input.
*/
public boolean isInputHeadset() {
return mIsInputHeadset;
}
/**
- * @returns true if the device is a headset for purposes of playback.
+ * @returns true if the device is a headset for purposes of output.
*/
public boolean isOutputHeadset() {
return mIsOutputHeadset;
}
/**
+ * @returns true if input jack is detected or jack detection is not supported.
+ */
+ private synchronized boolean isInputJackConnected() {
+ if (mJackDetector == null) {
+ return true; // If jack detect isn't supported, say it's connected.
+ }
+ return mJackDetector.isInputJackConnected();
+ }
+
+ /**
+ * @returns true if input jack is detected or jack detection is not supported.
+ */
+ private synchronized boolean isOutputJackConnected() {
+ if (mJackDetector == null) {
+ return true; // if jack detect isn't supported, say it's connected.
+ }
+ return mJackDetector.isOutputJackConnected();
+ }
+
+ /** Begins a jack-detection thread. */
+ private synchronized void startJackDetect() {
+ // If no jack detect capabilities exist, mJackDetector will be null.
+ mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
+ }
+
+ /** Stops a jack-detection thread. */
+ private synchronized void stopJackDetect() {
+ if (mJackDetector != null) {
+ mJackDetector.pleaseStop();
+ }
+ mJackDetector = null;
+ }
+
+ /** Start using this device as the selected USB Audio Device. */
+ public synchronized void start() {
+ mSelected = true;
+ mInputState = 0;
+ mOutputState = 0;
+ startJackDetect();
+ updateWiredDeviceConnectionState(true);
+ }
+
+ /** Stop using this device as the selected USB Audio Device. */
+ public synchronized void stop() {
+ stopJackDetect();
+ updateWiredDeviceConnectionState(false);
+ mSelected = false;
+ }
+
+ /** Updates AudioService with the connection state of the alsaDevice.
+ * Checks ALSA Jack state for inputs and outputs before reporting.
+ */
+ public synchronized void updateWiredDeviceConnectionState(boolean enable) {
+ if (!mSelected) {
+ Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!");
+ return;
+ }
+ String alsaCardDeviceString = getAlsaCardDeviceString();
+ if (alsaCardDeviceString == null) {
+ return;
+ }
+ try {
+ // Output Device
+ if (mHasOutput) {
+ int device = mIsOutputHeadset
+ ? AudioSystem.DEVICE_OUT_USB_HEADSET
+ : AudioSystem.DEVICE_OUT_USB_DEVICE;
+ if (DEBUG) {
+ Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device)
+ + " addr:" + alsaCardDeviceString
+ + " name:" + mDeviceName);
+ }
+ boolean connected = isOutputJackConnected();
+ Slog.i(TAG, "OUTPUT JACK connected: " + connected);
+ int outputState = (enable && connected) ? 1 : 0;
+ if (outputState != mOutputState) {
+ mOutputState = outputState;
+ mAudioService.setWiredDeviceConnectionState(device, outputState,
+ alsaCardDeviceString,
+ mDeviceName, TAG);
+ }
+ }
+
+ // Input Device
+ if (mHasInput) {
+ int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
+ : AudioSystem.DEVICE_IN_USB_DEVICE;
+ boolean connected = isInputJackConnected();
+ Slog.i(TAG, "INPUT JACK connected: " + connected);
+ int inputState = (enable && connected) ? 1 : 0;
+ if (inputState != mInputState) {
+ mInputState = inputState;
+ mAudioService.setWiredDeviceConnectionState(
+ device, inputState, alsaCardDeviceString,
+ mDeviceName, TAG);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+ }
+ }
+
+
+ /**
* @Override
* @returns a string representation of the object.
*/
- public String toString() {
+ public synchronized String toString() {
return "UsbAlsaDevice: [card: " + mCardNum
+ ", device: " + mDeviceNum
+ ", name: " + mDeviceName
- + ", hasPlayback: " + mHasPlayback
- + ", hasCapture: " + mHasCapture + "]";
+ + ", hasOutput: " + mHasOutput
+ + ", hasInput: " + mHasInput + "]";
}
/**
* Write a description of the device to a dump stream.
*/
- public void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
+ public synchronized void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
long token = dump.start(idName, id);
dump.write("card", UsbAlsaDeviceProto.CARD, mCardNum);
dump.write("device", UsbAlsaDeviceProto.DEVICE, mDeviceNum);
dump.write("name", UsbAlsaDeviceProto.NAME, mDeviceName);
- dump.write("has_playback", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasPlayback);
- dump.write("has_capture", UsbAlsaDeviceProto.HAS_CAPTURE, mHasCapture);
+ dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasOutput);
+ dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasInput);
dump.write("address", UsbAlsaDeviceProto.ADDRESS, mDeviceAddress);
dump.end(token);
}
// called by logDevices
- String toShortString() {
+ synchronized String toShortString() {
return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]";
}
- String getDeviceName() {
+ synchronized String getDeviceName() {
return mDeviceName;
}
- void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
+ synchronized void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
mDeviceName = deviceName;
mDeviceDescription = deviceDescription;
}
@@ -155,8 +282,8 @@
UsbAlsaDevice other = (UsbAlsaDevice) obj;
return (mCardNum == other.mCardNum
&& mDeviceNum == other.mDeviceNum
- && mHasPlayback == other.mHasPlayback
- && mHasCapture == other.mHasCapture
+ && mHasOutput == other.mHasOutput
+ && mHasInput == other.mHasInput
&& mIsInputHeadset == other.mIsInputHeadset
&& mIsOutputHeadset == other.mIsOutputHeadset);
}
@@ -170,8 +297,8 @@
int result = 1;
result = prime * result + mCardNum;
result = prime * result + mDeviceNum;
- result = prime * result + (mHasPlayback ? 0 : 1);
- result = prime * result + (mHasCapture ? 0 : 1);
+ result = prime * result + (mHasOutput ? 0 : 1);
+ result = prime * result + (mHasInput ? 0 : 1);
result = prime * result + (mIsInputHeadset ? 0 : 1);
result = prime * result + (mIsOutputHeadset ? 0 : 1);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
new file mode 100644
index 0000000..c498847
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+/**
+ * Detects and reports ALSA jack state and events.
+ */
+public final class UsbAlsaJackDetector implements Runnable {
+ private static final String TAG = "UsbAlsaJackDetector";
+
+ private static native boolean nativeHasJackDetect(int card);
+ private native boolean nativeJackDetect(int card);
+ private native boolean nativeOutputJackConnected(int card);
+ private native boolean nativeInputJackConnected(int card);
+
+ private boolean mStopJackDetect = false;
+ private UsbAlsaDevice mAlsaDevice;
+
+ /* use startJackDetect to create a UsbAlsaJackDetector */
+ private UsbAlsaJackDetector(UsbAlsaDevice device) {
+ mAlsaDevice = device;
+ }
+
+ /** If jack detection is detected on the given Alsa Device,
+ * create and return a UsbAlsaJackDetector which will update wired device state
+ * each time a jack detection event is registered.
+ *
+ * @returns UsbAlsaJackDetector if jack detect is supported, or null.
+ */
+ public static UsbAlsaJackDetector startJackDetect(UsbAlsaDevice device) {
+ if (!nativeHasJackDetect(device.getCardNum())) {
+ return null;
+ }
+ UsbAlsaJackDetector jackDetector = new UsbAlsaJackDetector(device);
+
+ // This thread will exit once the USB device disappears.
+ // It can also be convinced to stop with pleaseStop().
+ new Thread(jackDetector, "USB jack detect thread").start();
+ return jackDetector;
+ }
+
+ public boolean isInputJackConnected() {
+ return nativeInputJackConnected(mAlsaDevice.getCardNum());
+ }
+
+ public boolean isOutputJackConnected() {
+ return nativeOutputJackConnected(mAlsaDevice.getCardNum());
+ }
+
+ /**
+ * Stop the jack detect thread from calling back into UsbAlsaDevice.
+ * This doesn't force the thread to stop (which is deprecated in java and dangerous due to
+ * locking issues), but will cause the thread to exit at the next safe opportunity.
+ */
+ public void pleaseStop() {
+ synchronized (this) {
+ mStopJackDetect = true;
+ }
+ }
+
+ /**
+ * Called by nativeJackDetect each time a jack detect event is reported.
+ * @return false when the jackDetect thread should stop. true otherwise.
+ */
+ public boolean jackDetectCallback() {
+ synchronized (this) {
+ if (mStopJackDetect) {
+ return false;
+ }
+ mAlsaDevice.updateWiredDeviceConnectionState(true);
+ }
+ return true;
+ }
+
+ /**
+ * This will call jackDetectCallback each time it detects a jack detect event.
+ * If jackDetectCallback returns false, this function will return.
+ */
+ public void run() {
+ nativeJackDetect(mAlsaDevice.getCardNum());
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 0c5f8f1..2f1c516 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,11 +20,9 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbDevice;
-import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.usb.UsbAlsaManagerProto;
@@ -32,7 +30,6 @@
import com.android.internal.alsa.AlsaCardsParser;
import com.android.internal.util.dump.DualDumpOutputStream;
-import com.android.server.audio.AudioService;
import com.android.server.usb.descriptors.UsbDescriptorParser;
import libcore.io.IoUtils;
@@ -58,6 +55,7 @@
// this is needed to map USB devices to ALSA Audio Devices, especially to remove an
// ALSA device when we are notified that its associated USB device has been removed.
private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>();
+ private UsbAlsaDevice mSelectedDevice;
/**
* List of connected MIDI devices
@@ -78,17 +76,19 @@
ServiceManager.getService(Context.AUDIO_SERVICE));
}
- // Notifies AudioService when a device is added or removed
- // audioDevice - the AudioDevice that was added or removed
- // enabled - if true, we're connecting a device (it's arrived), else disconnecting
- private void notifyDeviceState(UsbAlsaDevice alsaDevice, boolean enabled) {
+ /**
+ * Select the AlsaDevice to be used for AudioService.
+ * AlsaDevice.start() notifies AudioService of it's connected state.
+ *
+ * @param alsaDevice The selected UsbAlsaDevice for system USB audio.
+ */
+ private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) {
if (DEBUG) {
- Slog.d(TAG, "notifyDeviceState " + enabled + " " + alsaDevice);
+ Slog.d(TAG, "selectAlsaDevice " + alsaDevice);
}
- if (mAudioService == null) {
- Slog.e(TAG, "no AudioService");
- return;
+ if (mSelectedDevice != null) {
+ deselectAlsaDevice();
}
// FIXME Does not yet handle the case where the setting is changed
@@ -102,40 +102,14 @@
return;
}
- int state = (enabled ? 1 : 0);
- int cardNum = alsaDevice.getCardNum();
- int deviceNum = alsaDevice.getDeviceNum();
- if (cardNum < 0 || deviceNum < 0) {
- Slog.e(TAG, "Invalid alsa card or device alsaCard: " + cardNum
- + " alsaDevice: " + deviceNum);
- return;
- }
+ mSelectedDevice = alsaDevice;
+ alsaDevice.start();
+ }
- String address = AudioService.makeAlsaAddressString(cardNum, deviceNum);
- try {
- // Playback Device
- if (alsaDevice.hasPlayback()) {
- int device = alsaDevice.isOutputHeadset()
- ? AudioSystem.DEVICE_OUT_USB_HEADSET
- : AudioSystem.DEVICE_OUT_USB_DEVICE;
- if (DEBUG) {
- Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
- " addr:" + address + " name:" + alsaDevice.getDeviceName());
- }
- mAudioService.setWiredDeviceConnectionState(
- device, state, address, alsaDevice.getDeviceName(), TAG);
- }
-
- // Capture Device
- if (alsaDevice.hasCapture()) {
- int device = alsaDevice.isInputHeadset()
- ? AudioSystem.DEVICE_IN_USB_HEADSET
- : AudioSystem.DEVICE_IN_USB_DEVICE;
- mAudioService.setWiredDeviceConnectionState(
- device, state, address, alsaDevice.getDeviceName(), TAG);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+ private synchronized void deselectAlsaDevice() {
+ if (mSelectedDevice != null) {
+ mSelectedDevice.stop();
+ mSelectedDevice = null;
}
}
@@ -168,7 +142,7 @@
Slog.d(TAG, " alsaDevice:" + alsaDevice);
}
if (alsaDevice != null) {
- notifyDeviceState(alsaDevice, true /*enabled*/);
+ selectAlsaDevice(alsaDevice);
}
return alsaDevice;
} else {
@@ -202,16 +176,21 @@
if (hasInput || hasOutput) {
boolean isInputHeadset = parser.isInputHeadset();
boolean isOutputHeadset = parser.isOutputHeadset();
- UsbAlsaDevice alsaDevice =
- new UsbAlsaDevice(cardRec.getCardNum(), 0 /*device*/, deviceAddress,
- hasOutput, hasInput, isInputHeadset, isOutputHeadset);
- alsaDevice.setDeviceNameAndDescription(
- cardRec.getCardName(), cardRec.getCardDescription());
- mAlsaDevices.add(0, alsaDevice);
- // Select it
+ if (mAudioService == null) {
+ Slog.e(TAG, "no AudioService");
+ return;
+ }
+
+ UsbAlsaDevice alsaDevice =
+ new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
+ deviceAddress, hasOutput, hasInput,
+ isInputHeadset, isOutputHeadset);
if (alsaDevice != null) {
- notifyDeviceState(alsaDevice, true /*enabled*/);
+ alsaDevice.setDeviceNameAndDescription(
+ cardRec.getCardName(), cardRec.getCardDescription());
+ mAlsaDevices.add(0, alsaDevice);
+ selectAlsaDevice(alsaDevice);
}
}
@@ -256,7 +235,7 @@
}
}
- /* package */ void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
+ /* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
if (DEBUG) {
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
}
@@ -264,13 +243,9 @@
// Audio
UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress);
Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice);
- if (alsaDevice != null) {
- if (alsaDevice.hasPlayback() || alsaDevice.hasCapture()) {
- notifyDeviceState(alsaDevice, false /*enabled*/);
-
- // if there any external devices left, select one of them
- selectDefaultDevice();
- }
+ if (alsaDevice != null && alsaDevice == mSelectedDevice) {
+ deselectAlsaDevice();
+ selectDefaultDevice(); // if there any external devices left, select one of them
}
// MIDI
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index f6c5532..f186ee5 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -17,6 +17,7 @@
package android.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -48,18 +49,12 @@
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
}
- @Test
- public void testParcelUnparcel() throws Exception {
- assertParcelingIsLossless(new IpSecConfig());
-
+ private IpSecConfig getSampleConfig() {
IpSecConfig c = new IpSecConfig();
c.setMode(IpSecTransform.MODE_TUNNEL);
c.setSourceAddress("0.0.0.0");
c.setDestinationAddress("1.2.3.4");
- c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
- c.setEncapSocketResourceId(7);
- c.setEncapRemotePort(22);
- c.setNattKeepaliveInterval(42);
+ c.setSpiResourceId(1984);
c.setEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.CRYPT_AES_CBC,
@@ -68,7 +63,37 @@
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
- c.setSpiResourceId(1984);
+ c.setAuthenticatedEncryption(
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+ new byte[] {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
+ },
+ 128));
+ c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
+ c.setEncapSocketResourceId(7);
+ c.setEncapRemotePort(22);
+ c.setNattKeepaliveInterval(42);
+ c.setMarkValue(12);
+ c.setMarkMask(23);
+
+ return c;
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ IpSecConfig original = getSampleConfig();
+ IpSecConfig copy = new IpSecConfig(original);
+
+ assertTrue(IpSecConfig.equals(original, copy));
+ assertFalse(original == copy);
+ }
+
+ @Test
+ public void testParcelUnparcel() throws Exception {
+ assertParcelingIsLossless(new IpSecConfig());
+
+ IpSecConfig c = getSampleConfig();
assertParcelingIsLossless(c);
}
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java
new file mode 100644
index 0000000..b4342df
--- /dev/null
+++ b/tests/net/java/android/net/IpSecTransformTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.net;
+
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link IpSecTransform}. */
+@SmallTest
+@RunWith(JUnit4.class)
+public class IpSecTransformTest {
+
+ @Test
+ public void testCreateTransformCopiesConfig() {
+ // Create a config with a few parameters to make sure it's not empty
+ IpSecConfig config = new IpSecConfig();
+ config.setSourceAddress("0.0.0.0");
+ config.setDestinationAddress("1.2.3.4");
+ config.setSpiResourceId(1984);
+
+ IpSecTransform preModification = new IpSecTransform(null, config);
+
+ config.setSpiResourceId(1985);
+ IpSecTransform postModification = new IpSecTransform(null, config);
+
+ assertFalse(IpSecTransform.equals(preModification, postModification));
+ }
+
+ @Test
+ public void testCreateTransformsWithSameConfigEqual() {
+ // Create a config with a few parameters to make sure it's not empty
+ IpSecConfig config = new IpSecConfig();
+ config.setSourceAddress("0.0.0.0");
+ config.setDestinationAddress("1.2.3.4");
+ config.setSpiResourceId(1984);
+
+ IpSecTransform config1 = new IpSecTransform(null, config);
+ IpSecTransform config2 = new IpSecTransform(null, config);
+
+ assertFalse(IpSecTransform.equals(config1, config2));
+ }
+}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 5831875..249557a 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -414,59 +414,70 @@
public:
using xml::ConstVisitor::Visit;
+ XmlPrinter(Printer* printer) : printer_(printer) {
+ }
+
void Visit(const xml::Element* el) override {
- const size_t previous_size = prefix_.size();
-
for (const xml::NamespaceDecl& decl : el->namespace_decls) {
- std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri
- << " (line=" << decl.line_number << ")\n";
- prefix_ += " ";
+ printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
+ decl.line_number));
+ printer_->Indent();
}
- std::cerr << prefix_ << "E: ";
+ printer_->Print("E: ");
if (!el->namespace_uri.empty()) {
- std::cerr << el->namespace_uri << ":";
+ printer_->Print(el->namespace_uri);
+ printer_->Print(":");
}
- std::cerr << el->name << " (line=" << el->line_number << ")\n";
+ printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
+ printer_->Indent();
for (const xml::Attribute& attr : el->attributes) {
- std::cerr << prefix_ << " A: ";
+ printer_->Print("A: ");
if (!attr.namespace_uri.empty()) {
- std::cerr << attr.namespace_uri << ":";
+ printer_->Print(attr.namespace_uri);
+ printer_->Print(":");
}
- std::cerr << attr.name;
+ printer_->Print(attr.name);
if (attr.compiled_attribute) {
- std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
- << ")";
+ printer_->Print("(");
+ printer_->Print(
+ attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
+ printer_->Print(")");
}
- std::cerr << "=";
+ printer_->Print("=");
if (attr.compiled_value != nullptr) {
- std::cerr << *attr.compiled_value;
+ attr.compiled_value->PrettyPrint(printer_);
} else {
- std::cerr << attr.value;
+ printer_->Print(attr.value);
}
- std::cerr << "\n";
+ printer_->Println();
}
- prefix_ += " ";
+ printer_->Indent();
xml::ConstVisitor::Visit(el);
- prefix_.resize(previous_size);
+ printer_->Undent();
+ printer_->Undent();
+
+ for (size_t i = 0; i < el->namespace_decls.size(); i++) {
+ printer_->Undent();
+ }
}
void Visit(const xml::Text* text) override {
- std::cerr << prefix_ << "T: '" << text->text << "'\n";
+ printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
}
private:
- std::string prefix_;
+ Printer* printer_;
};
} // namespace
-void Debug::DumpXml(const xml::XmlResource& doc) {
- XmlPrinter printer;
- doc.root->Accept(&printer);
+void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
+ XmlPrinter xml_visitor(printer);
+ doc.root->Accept(&xml_visitor);
}
} // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 6209a04..382707e 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -37,7 +37,7 @@
text::Printer* printer);
static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
static void DumpHex(const void* data, size_t len);
- static void DumpXml(const xml::XmlResource& doc);
+ static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
};
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 20a9f41..ac28227 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -222,7 +222,9 @@
} else if (manifest != nullptr && path == "AndroidManifest.xml") {
BigBuffer buffer(8192);
- XmlFlattener xml_flattener(&buffer, {});
+ XmlFlattenerOptions xml_flattener_options;
+ xml_flattener_options.use_utf16 = true;
+ XmlFlattener xml_flattener(&buffer, xml_flattener_options);
if (!xml_flattener.Consume(context, manifest)) {
context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
return false;
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 02ac86c..628466d 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -520,6 +520,10 @@
return util::make_unique<BinaryPrimitive>(value);
}
+std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t val) {
+ return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, val);
+}
+
std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 36f6c2b..f83d49e 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -165,6 +165,9 @@
*/
std::unique_ptr<BinaryPrimitive> TryParseInt(const android::StringPiece& str);
+// Returns an integer BinaryPrimitive.
+std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value);
+
/*
* Returns a BinaryPrimitve object representing a floating point number
* (float, dimension, etc) if the string was parsed as one.
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 3d2fb55..8e7e5e5 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -38,6 +38,13 @@
namespace aapt {
+struct DumpOptions {
+ DebugPrintTableOptions print_options;
+
+ // The path to a file within an APK to dump.
+ Maybe<std::string> file_to_dump_path;
+};
+
static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
switch (type) {
case ResourceFile::Type::kPng:
@@ -69,8 +76,52 @@
printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
}
+static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto,
+ text::Printer* printer) {
+ std::unique_ptr<xml::XmlResource> doc;
+ if (proto) {
+ std::unique_ptr<io::InputStream> in = file->OpenInputStream();
+ if (in == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
+ return false;
+ }
+
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ pb::XmlNode pb_node;
+ if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML");
+ return false;
+ }
+
+ std::string err;
+ doc = DeserializeXmlResourceFromPb(pb_node, &err);
+ if (doc == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML");
+ return false;
+ }
+ printer->Println("Proto XML");
+ } else {
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (data == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
+ return false;
+ }
+
+ std::string err;
+ doc = xml::Inflate(data->data(), data->size(), &err);
+ if (doc == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML");
+ return false;
+ }
+ printer->Println("Binary XML");
+ }
+
+ Debug::DumpXml(*doc, printer);
+ return true;
+}
+
static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
- const DebugPrintTableOptions& print_options) {
+ const DumpOptions& options) {
// Use a smaller buffer so that there is less latency for dumping to stdout.
constexpr size_t kStdOutBufferSize = 1024u;
io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
@@ -80,7 +131,10 @@
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
if (zip) {
ResourceTable table;
+ bool proto = false;
if (io::IFile* file = zip->FindFile("resources.pb")) {
+ proto = true;
+
std::unique_ptr<io::IData> data = file->OpenAsData();
if (data == nullptr) {
context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
@@ -98,8 +152,6 @@
<< "failed to parse table: " << err);
return false;
}
-
- printer.Println("Proto APK");
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
@@ -112,12 +164,26 @@
if (!parser.Parse()) {
return false;
}
-
- printer.Println("Binary APK");
}
- Debug::PrintTable(table, print_options, &printer);
- return true;
+ if (!options.file_to_dump_path) {
+ if (proto) {
+ printer.Println("Proto APK");
+ } else {
+ printer.Println("Binary APK");
+ }
+ Debug::PrintTable(table, options.print_options, &printer);
+ return true;
+ }
+
+ io::IFile* file = zip->FindFile(options.file_to_dump_path.value());
+ if (file == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path)
+ << "file '" << options.file_to_dump_path.value()
+ << "' not found in APK");
+ return false;
+ }
+ return DumpXmlFile(context, file, proto, &printer);
}
err.clear();
@@ -159,7 +225,7 @@
}
printer.Indent();
- Debug::PrintTable(table, print_options, &printer);
+ Debug::PrintTable(table, options.print_options, &printer);
printer.Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
printer.Println("kResFile");
@@ -243,10 +309,13 @@
int Dump(const std::vector<StringPiece>& args) {
bool verbose = false;
bool no_values = false;
+ DumpOptions options;
Flags flags = Flags()
.OptionalSwitch("--no-values",
"Suppresses output of values when displaying resource tables.",
&no_values)
+ .OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
+ &options.file_to_dump_path)
.OptionalSwitch("-v", "increase verbosity of output", &verbose);
if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
return 1;
@@ -255,11 +324,10 @@
DumpContext context;
context.SetVerbose(verbose);
- DebugPrintTableOptions dump_table_options;
- dump_table_options.show_sources = true;
- dump_table_options.show_values = !no_values;
+ options.print_options.show_sources = true;
+ options.print_options.show_values = !no_values;
for (const std::string& arg : flags.GetArgs()) {
- if (!TryDumpFile(&context, arg, dump_table_options)) {
+ if (!TryDumpFile(&context, arg, options)) {
return 1;
}
}
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index eabeb47..902334b 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -20,6 +20,7 @@
#include <functional>
#include <map>
#include <memory>
+#include <string>
#include <utility>
#include "android-base/file.h"
@@ -93,6 +94,7 @@
};
NoopDiagnostics noop_;
+/** Returns the value of the label attribute for a given element. */
std::string GetLabel(const Element* element, IDiagnostics* diag) {
std::string label;
for (const auto& attr : element->attributes) {
@@ -108,6 +110,18 @@
return label;
}
+/** Returns the value of the version-code-order attribute for a given element. */
+Maybe<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
+ const xml::Attribute* version = element->FindAttribute("", "version-code-order");
+ if (version == nullptr) {
+ std::string label = GetLabel(element, diag);
+ diag->Error(DiagMessage() << "No version-code-order found for element '" << element->name
+ << "' with label '" << label << "'");
+ return {};
+ }
+ return std::stoi(version->value);
+}
+
/** XML node visitor that removes all of the namespace URIs from the node and all children. */
class NamespaceVisitor : public xml::Visitor {
public:
@@ -437,26 +451,37 @@
// Convert from a parsed configuration to a list of artifacts for processing.
const std::string& apk_name = file::GetFilename(apk_path).to_string();
std::vector<OutputArtifact> output_artifacts;
- bool has_errors = false;
PostProcessingConfiguration& config = maybe_config.value();
- config.SortArtifacts();
+ bool valid = true;
int version = 1;
+
for (const ConfiguredArtifact& artifact : config.artifacts) {
Maybe<OutputArtifact> output_artifact = ToOutputArtifact(artifact, apk_name, config, diag_);
if (!output_artifact) {
// Defer return an error condition so that all errors are reported.
- has_errors = true;
+ valid = false;
} else {
output_artifact.value().version = version++;
output_artifacts.push_back(std::move(output_artifact.value()));
}
}
- if (has_errors) {
+ if (!config.ValidateVersionCodeOrdering(diag_)) {
+ diag_->Error(DiagMessage() << "could not validate post processing configuration");
+ valid = false;
+ }
+
+ if (valid) {
+ // Sorting artifacts requires that all references are valid as it uses them to determine order.
+ config.SortArtifacts();
+ }
+
+ if (!valid) {
return {};
}
+
return {output_artifacts};
}
@@ -509,8 +534,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->abi_groups);
bool valid = true;
+ OrderedEntry<Abi>& entry = config->abi_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case for empty abi-group tag. Label will be used as the ABI.
if (root_element->GetChildElements().empty()) {
@@ -519,7 +551,7 @@
return false;
}
group.push_back(abi->second);
- return true;
+ return valid;
}
for (auto* child : root_element->GetChildElements()) {
@@ -553,8 +585,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->screen_density_groups);
bool valid = true;
+ OrderedEntry<ConfigDescription>& entry = config->screen_density_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case for empty screen-density-group tag. Label will be used as the screen density.
if (root_element->GetChildElements().empty()) {
@@ -613,8 +652,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->locale_groups);
bool valid = true;
+ OrderedEntry<ConfigDescription>& entry = config->locale_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case to auto insert a locale for an empty group. Label will be used for locale.
if (root_element->GetChildElements().empty()) {
@@ -728,8 +774,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->gl_texture_groups);
bool valid = true;
+ OrderedEntry<GlTexture>& entry = config->gl_texture_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
GlTexture result;
for (auto* child : root_element->GetChildElements()) {
@@ -771,8 +824,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->device_feature_groups);
bool valid = true;
+ OrderedEntry<DeviceFeature>& entry = config->device_feature_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
for (auto* child : root_element->GetChildElements()) {
if (child->name != "supports-feature") {
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index a583057..f071a69 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -33,18 +33,31 @@
template <typename T>
struct OrderedEntry {
- size_t order;
+ int32_t order;
std::vector<T> entry;
};
-/** A mapping of group labels to group of configuration items. */
-template <class T>
-using Group = std::unordered_map<std::string, OrderedEntry<T>>;
-
/** A mapping of group label to a single configuration item. */
template <class T>
using Entry = std::unordered_map<std::string, T>;
+/** A mapping of group labels to group of configuration items. */
+template <class T>
+using Group = Entry<OrderedEntry<T>>;
+
+template<typename T>
+bool IsGroupValid(const Group<T>& group, const std::string& name, IDiagnostics* diag) {
+ std::set<int32_t> orders;
+ for (const auto& p : group) {
+ orders.insert(p.second.order);
+ }
+ bool valid = orders.size() == group.size();
+ if (!valid) {
+ diag->Error(DiagMessage() << name << " have overlapping version-code-order attributes");
+ }
+ return valid;
+}
+
/** Retrieves an entry from the provided Group, creating a new instance if one does not exist. */
template <typename T>
std::vector<T>& GetOrCreateGroup(std::string label, Group<T>* group) {
@@ -93,7 +106,7 @@
private:
template <typename T>
- inline size_t GetGroupOrder(const Group<T>& groups, const Maybe<std::string>& label) {
+ inline size_t GetGroupOrder(const Entry<T>& groups, const Maybe<std::string>& label) {
if (!label) {
return std::numeric_limits<size_t>::max();
}
@@ -141,6 +154,15 @@
Group<GlTexture> gl_texture_groups;
Entry<AndroidSdk> android_sdks;
+ bool ValidateVersionCodeOrdering(IDiagnostics* diag) {
+ bool valid = IsGroupValid(abi_groups, "abi-groups", diag);
+ valid &= IsGroupValid(screen_density_groups, "screen-density-groups", diag);
+ valid &= IsGroupValid(locale_groups, "locale-groups", diag);
+ valid &= IsGroupValid(device_feature_groups, "device-feature-groups", diag);
+ valid &= IsGroupValid(gl_texture_groups, "gl-texture-groups", diag);
+ return valid;
+ }
+
/**
* Sorts the configured artifacts based on the ordering of the groups in the configuration file.
* The only exception to this rule is Android SDK versions. Larger SDK versions will have a larger
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 0329846..febbb2e 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -82,22 +82,22 @@
constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
<post-process xmlns="http://schemas.android.com/tools/aapt">
<abi-groups>
- <abi-group label="arm">
- <abi>armeabi-v7a</abi>
- <abi>arm64-v8a</abi>
- </abi-group>
- <abi-group label="other">
+ <abi-group label="other" version-code-order="2">
<abi>x86</abi>
<abi>mips</abi>
</abi-group>
+ <abi-group label="arm" version-code-order="1">
+ <abi>armeabi-v7a</abi>
+ <abi>arm64-v8a</abi>
+ </abi-group>
</abi-groups>
<screen-density-groups>
- <screen-density-group label="large">
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
</screen-density-group>
- <screen-density-group label="alldpi">
+ <screen-density-group label="alldpi" version-code-order="1">
<screen-density>ldpi</screen-density>
<screen-density>mdpi</screen-density>
<screen-density>hdpi</screen-density>
@@ -107,17 +107,20 @@
</screen-density-group>
</screen-density-groups>
<locale-groups>
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="1">
<locale>en</locale>
<locale>es</locale>
<locale>fr</locale>
<locale>de</locale>
</locale-group>
- <locale-group label="north-america">
+ <locale-group label="north-america" version-code-order="2">
<locale>en</locale>
<locale>es-rMX</locale>
<locale>fr-rCA</locale>
</locale-group>
+ <locale-group label="all" version-code-order="-1">
+ <locale />
+ </locale-group>
</locale-groups>
<android-sdks>
<android-sdk
@@ -131,14 +134,14 @@
</android-sdk>
</android-sdks>
<gl-texture-groups>
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="2">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/*</texture-path>
</gl-texture>
</gl-texture-group>
</gl-texture-groups>
<device-feature-groups>
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="2">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
</device-feature-group>
</device-feature-groups>
@@ -188,19 +191,22 @@
auto& arm = config.abi_groups["arm"];
auto& other = config.abi_groups["other"];
- EXPECT_EQ(arm.order, 1ul);
- EXPECT_EQ(other.order, 2ul);
+ EXPECT_EQ(arm.order, 1);
+ EXPECT_EQ(other.order, 2);
auto& large = config.screen_density_groups["large"];
auto& alldpi = config.screen_density_groups["alldpi"];
- EXPECT_EQ(large.order, 1ul);
- EXPECT_EQ(alldpi.order, 2ul);
+ EXPECT_EQ(large.order, 2);
+ EXPECT_EQ(alldpi.order, 1);
auto& north_america = config.locale_groups["north-america"];
auto& europe = config.locale_groups["europe"];
+ auto& all = config.locale_groups["all"];
// Checked in reverse to make sure access order does not matter.
- EXPECT_EQ(north_america.order, 2ul);
- EXPECT_EQ(europe.order, 1ul);
+ EXPECT_EQ(north_america.order, 2);
+ EXPECT_EQ(europe.order, 1);
+ EXPECT_EQ(all.order, -1);
+ EXPECT_EQ(3ul, config.locale_groups.size());
}
TEST_F(ConfigurationParserTest, ValidateFile) {
@@ -392,7 +398,7 @@
TEST_F(ConfigurationParserTest, AbiGroupAction) {
static constexpr const char* xml = R"xml(
- <abi-group label="arm">
+ <abi-group label="arm" version-code-order="2">
<!-- First comment. -->
<abi>
armeabi-v7a
@@ -415,7 +421,8 @@
}
TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup) {
- static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
+ static constexpr const char* xml =
+ R"xml(<abi-group label="arm64-v8a" version-code-order="3"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -426,12 +433,23 @@
EXPECT_THAT(config.abi_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.abi_groups.count("arm64-v8a"));
- auto& out = config.abi_groups["arm64-v8a"].entry;
- ASSERT_THAT(out, ElementsAre(Abi::kArm64V8a));
+ auto& out = config.abi_groups["arm64-v8a"];
+ ASSERT_THAT(out.entry, ElementsAre(Abi::kArm64V8a));
+ EXPECT_EQ(3, out.order);
+}
+
+TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup_NoOrder) {
+ static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, AbiGroupAction_InvalidEmptyGroup) {
- static constexpr const char* xml = R"xml(<abi-group label="arm"/>)xml";
+ static constexpr const char* xml = R"xml(<abi-group label="arm" order="2"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -442,7 +460,7 @@
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) {
static constexpr const char* xml = R"xml(
- <screen-density-group label="large">
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>
xxhdpi
@@ -471,7 +489,8 @@
}
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup) {
- static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
+ static constexpr const char* xml =
+ R"xml(<screen-density-group label="xhdpi" version-code-order="4"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -485,8 +504,19 @@
ConfigDescription xhdpi;
xhdpi.density = ResTable_config::DENSITY_XHIGH;
- auto& out = config.screen_density_groups["xhdpi"].entry;
- ASSERT_THAT(out, ElementsAre(xhdpi));
+ auto& out = config.screen_density_groups["xhdpi"];
+ EXPECT_THAT(out.entry, ElementsAre(xhdpi));
+ EXPECT_EQ(4, out.order);
+}
+
+TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup_NoVersion) {
+ static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_InvalidEmtpyGroup) {
@@ -501,7 +531,7 @@
TEST_F(ConfigurationParserTest, LocaleGroupAction) {
static constexpr const char* xml = R"xml(
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="2">
<locale>en</locale>
<locale>es</locale>
<locale>fr</locale>
@@ -528,7 +558,7 @@
}
TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup) {
- static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
+ static constexpr const char* xml = R"xml(<locale-group label="en" version-code-order="6"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -539,11 +569,22 @@
ASSERT_EQ(1ul, config.locale_groups.size());
ASSERT_EQ(1u, config.locale_groups.count("en"));
- const auto& out = config.locale_groups["en"].entry;
+ const auto& out = config.locale_groups["en"];
ConfigDescription en = test::ParseConfigOrDie("en");
- ASSERT_THAT(out, ElementsAre(en));
+ EXPECT_THAT(out.entry, ElementsAre(en));
+ EXPECT_EQ(6, out.order);
+}
+
+TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup_NoOrder) {
+ static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, LocaleGroupAction_InvalidEmtpyGroup) {
@@ -695,7 +736,7 @@
TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
static constexpr const char* xml = R"xml(
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="2">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/main/*</texture-path>
<texture-path>
@@ -726,7 +767,7 @@
TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) {
static constexpr const char* xml = R"xml(
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="2">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
<supports-feature>
android.hardware.audio.pro
@@ -749,6 +790,30 @@
ASSERT_THAT(out, ElementsAre(low_latency, pro));
}
+TEST_F(ConfigurationParserTest, Group_Valid) {
+ Group<int32_t> group;
+ group["item1"].order = 1;
+ group["item2"].order = 2;
+ group["item3"].order = 3;
+ group["item4"].order = 4;
+ group["item5"].order = 5;
+ group["item6"].order = 6;
+
+ EXPECT_TRUE(IsGroupValid(group, "test", &diag_));
+}
+
+TEST_F(ConfigurationParserTest, Group_OverlappingOrder) {
+ Group<int32_t> group;
+ group["item1"].order = 1;
+ group["item2"].order = 2;
+ group["item3"].order = 3;
+ group["item4"].order = 2;
+ group["item5"].order = 5;
+ group["item6"].order = 1;
+
+ EXPECT_FALSE(IsGroupValid(group, "test", &diag_));
+}
+
// Artifact name parser test cases.
TEST(ArtifactTest, Simple) {
diff --git a/tools/aapt2/configuration/aapt2.xsd b/tools/aapt2/configuration/aapt2.xsd
index fb2f49b..a28e28b 100644
--- a/tools/aapt2/configuration/aapt2.xsd
+++ b/tools/aapt2/configuration/aapt2.xsd
@@ -81,6 +81,7 @@
<xsd:element name="gl-texture" type="gl-texture" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="gl-texture">
@@ -95,6 +96,7 @@
<xsd:element name="supports-feature" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="abi-group">
@@ -102,6 +104,7 @@
<xsd:element name="abi" type="abi-name" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:simpleType name="abi-name">
@@ -122,6 +125,7 @@
<xsd:element name="screen-density" type="screen-density" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:simpleType name="screen-density">
@@ -158,6 +162,7 @@
<xsd:element name="locale" type="locale" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="locale">
diff --git a/tools/aapt2/configuration/example/config.xml b/tools/aapt2/configuration/example/config.xml
index d8aba09..e6db2a0 100644
--- a/tools/aapt2/configuration/example/config.xml
+++ b/tools/aapt2/configuration/example/config.xml
@@ -36,25 +36,19 @@
</android-sdks>
<abi-groups>
- <abi-group label="arm">
+ <abi-group label="arm" version-code-order="1">
<abi>armeabi-v7a</abi>
<abi>arm64-v8a</abi>
</abi-group>
- <abi-group label="other">
+ <abi-group label="other" version-code-order="2">
<abi>x86</abi>
<abi>mips</abi>
</abi-group>
</abi-groups>
<screen-density-groups>
- <screen-density-group label="large">
- <screen-density>xhdpi</screen-density>
- <screen-density>xxhdpi</screen-density>
- <screen-density>xxxhdpi</screen-density>
- </screen-density-group>
-
- <screen-density-group label="alldpi">
+ <screen-density-group label="alldpi" version-code-order="1">
<screen-density>ldpi</screen-density>
<screen-density>mdpi</screen-density>
<screen-density>hdpi</screen-density>
@@ -62,29 +56,35 @@
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
</screen-density-group>
+
+ <screen-density-group label="large" version-code-order="2">
+ <screen-density>xhdpi</screen-density>
+ <screen-density>xxhdpi</screen-density>
+ <screen-density>xxxhdpi</screen-density>
+ </screen-density-group>
</screen-density-groups>
<locale-groups>
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="1">
<locale lang="en"/>
<locale lang="es"/>
<locale lang="fr"/>
<locale lang="de" compressed="true"/>
</locale-group>
- <locale-group label="north-america">
+ <locale-group label="north-america" version-code-order="2">
<locale lang="en"/>
<locale lang="es" region="MX"/>
<locale lang="fr" region="CA" compressed="true"/>
</locale-group>
- <locale-group label="all">
+ <locale-group label="all" version-code-order="0">
<locale compressed="true"/>
</locale-group>
</locale-groups>
<gl-texture-groups>
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="1">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/*</texture-path>
</gl-texture>
@@ -92,7 +92,7 @@
</gl-texture-groups>
<device-feature-groups>
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="1">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
</device-feature-group>
</device-feature-groups>
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 991faad..588b331 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -322,22 +322,56 @@
std::unique_ptr<xml::Element> new_screens_el = util::make_unique<xml::Element>();
new_screens_el->name = "compatible-screens";
screens_el = new_screens_el.get();
- manifest_el->InsertChild(0, std::move(new_screens_el));
+ manifest_el->AppendChild(std::move(new_screens_el));
} else {
// clear out the old element.
screens_el->GetChildElements().clear();
}
for (const auto& density : artifact.screen_densities) {
- std::unique_ptr<xml::Element> screen_el = util::make_unique<xml::Element>();
- screen_el->name = "screen";
- const char* density_str = density.toString().string();
- screen_el->attributes.push_back(xml::Attribute{kSchemaAndroid, "screenDensity", density_str});
- screens_el->AppendChild(std::move(screen_el));
+ AddScreens(density, screens_el);
}
}
return true;
}
+/**
+ * Adds a screen element with both screenSize and screenDensity set. Since we only know the density
+ * we add it for all screen sizes.
+ *
+ * This requires the resource IDs for the attributes from the framework library. Since these IDs are
+ * a part of the public API (and in public.xml) we hard code the values.
+ *
+ * The excert from the framework is as follows:
+ * <public type="attr" name="screenSize" id="0x010102ca" />
+ * <public type="attr" name="screenDensity" id="0x010102cb" />
+ */
+void MultiApkGenerator::AddScreens(const ConfigDescription& config, xml::Element* parent) {
+ // Hard coded integer representation of the supported screen sizes:
+ // small = 200
+ // normal = 300
+ // large = 400
+ // xlarge = 500
+ constexpr const uint32_t kScreenSizes[4] = {200, 300, 400, 500,};
+ constexpr const uint32_t kScreenSizeResourceId = 0x010102ca;
+ constexpr const uint32_t kScreenDensityResourceId = 0x010102cb;
+
+ for (uint32_t screen_size : kScreenSizes) {
+ std::unique_ptr<xml::Element> screen = util::make_unique<xml::Element>();
+ screen->name = "screen";
+
+ xml::Attribute* size = screen->FindOrCreateAttribute(kSchemaAndroid, "screenSize");
+ size->compiled_attribute = xml::AaptAttribute(Attribute(), {kScreenSizeResourceId});
+ size->compiled_value = ResourceUtils::MakeInt(screen_size);
+
+ xml::Attribute* density = screen->FindOrCreateAttribute(kSchemaAndroid, "screenDensity");
+ density->compiled_attribute = xml::AaptAttribute(Attribute(), {kScreenDensityResourceId});
+ density->compiled_value = ResourceUtils::MakeInt(config.density);
+
+
+ parent->AppendChild(std::move(screen));
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index 19f64cc..c858879 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -63,6 +63,11 @@
bool UpdateManifest(const configuration::OutputArtifact& artifact,
std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
+ /**
+ * Adds the <screen> elements to the parent node for the provided density configuration.
+ */
+ void AddScreens(const ConfigDescription& config, xml::Element* parent);
+
LoadedApk* apk_;
IAaptContext* context_;
};