Merge "[AVF] Make patch level diff flexible by a requirement" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index bd17d6d..0ca9789 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -25,6 +25,7 @@
"android.app.appfunctions.flags-aconfig-java",
"android.app.contextualsearch.flags-aconfig-java",
"android.app.flags-aconfig-java",
+ "android.app.jank.flags-aconfig-java",
"android.app.ondeviceintelligence-aconfig-java",
"android.app.smartspace.flags-aconfig-java",
"android.app.supervision.flags-aconfig-java",
@@ -77,6 +78,7 @@
"android.view.inputmethod.flags-aconfig-java",
"android.webkit.flags-aconfig-java",
"android.widget.flags-aconfig-java",
+ "art_exported_aconfig_flags_lib",
"backstage_power_flags_lib",
"backup_flags_lib",
"camera_platform_flags_core_java_lib",
@@ -139,6 +141,14 @@
libs: ["fake_device_config"],
}
+// ART
+java_aconfig_library {
+ name: "art_exported_aconfig_flags_lib",
+ aconfig_declarations: "art-aconfig-flags",
+ mode: "exported",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// Camera
java_aconfig_library {
name: "camera_platform_flags_core_java_lib",
@@ -1606,3 +1616,17 @@
aconfig_declarations: "interaction_jank_monitor_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// App Jank
+aconfig_declarations {
+ name: "android.app.jank.flags-aconfig",
+ package: "android.app.jank",
+ container: "system",
+ srcs: ["core/java/android/app/jank/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.app.jank.flags-aconfig-java",
+ aconfig_declarations: "android.app.jank.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index 258440f..5b9f2cb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -427,6 +427,7 @@
"modules-utils-expresslog",
"perfetto_trace_javastream_protos_jarjar",
"libaconfig_java_proto_nano",
+ "aconfig_device_paths_java",
],
}
diff --git a/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
index 237c747..80cd86c 100644
--- a/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,11 +34,11 @@
public class AdditionPerfTest {
@Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeAddConstantToLocalInt() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int result = 0;
while (state.keepRunning()) {
result += 123;
@@ -46,7 +46,7 @@
}
@Test
public void timeAddTwoLocalInts() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int result = 0;
int constant = 123;
while (state.keepRunning()) {
@@ -55,7 +55,7 @@
}
@Test
public void timeAddConstantToLocalLong() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
long result = 0;
while (state.keepRunning()) {
result += 123L;
@@ -63,7 +63,7 @@
}
@Test
public void timeAddTwoLocalLongs() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
long result = 0;
long constant = 123L;
while (state.keepRunning()) {
@@ -72,7 +72,7 @@
}
@Test
public void timeAddConstantToLocalFloat() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
float result = 0.0f;
while (state.keepRunning()) {
result += 123.0f;
@@ -80,7 +80,7 @@
}
@Test
public void timeAddTwoLocalFloats() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
float result = 0.0f;
float constant = 123.0f;
while (state.keepRunning()) {
@@ -89,7 +89,7 @@
}
@Test
public void timeAddConstantToLocalDouble() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
double result = 0.0;
while (state.keepRunning()) {
result += 123.0;
@@ -97,7 +97,7 @@
}
@Test
public void timeAddTwoLocalDoubles() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
double result = 0.0;
double constant = 123.0;
while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
index 1222bc2..2f6c378 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,11 +33,11 @@
public class ArrayCopyPerfTest {
@Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeManualArrayCopy() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
char[] src = new char[8192];
while (state.keepRunning()) {
char[] dst = new char[8192];
@@ -49,7 +49,7 @@
@Test
public void time_System_arrayCopy() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
char[] src = new char[8192];
while (state.keepRunning()) {
char[] dst = new char[8192];
@@ -59,7 +59,7 @@
@Test
public void time_Arrays_copyOf() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
char[] src = new char[8192];
while (state.keepRunning()) {
char[] dst = Arrays.copyOf(src, 8192);
@@ -68,7 +68,7 @@
@Test
public void time_Arrays_copyOfRange() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
char[] src = new char[8192];
while (state.keepRunning()) {
char[] dst = Arrays.copyOfRange(src, 0, 8192);
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
index 3f95e3e..d17add7 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,7 +38,7 @@
}
@Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Foo[] mArray = new Foo[27];
{
@@ -46,7 +46,7 @@
}
@Test
public void timeArrayIteration() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
int sum = 0;
for (int i = 0; i < mArray.length; i++) {
@@ -56,7 +56,7 @@
}
@Test
public void timeArrayIterationCached() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
int sum = 0;
Foo[] localArray = mArray;
@@ -69,7 +69,7 @@
}
@Test
public void timeArrayIterationForEach() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
int sum = 0;
for (Foo a: mArray) {
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
index 1423a13..3a57db8 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -39,7 +39,7 @@
int mSplat;
}
@Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
ArrayList<Foo> mList = new ArrayList<Foo>();
{
@@ -47,7 +47,7 @@
}
@Test
public void timeArrayListIterationIndexed() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
int sum = 0;
ArrayList<Foo> list = mList;
@@ -59,7 +59,7 @@
}
@Test
public void timeArrayListIterationForEach() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
int sum = 0;
for (Foo a : mList) {
diff --git a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
index 0283105..3fb3bc8 100644
--- a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,8 +38,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class BigIntegerPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
// A simple sum of products computation, mostly so we can check timing in the
// absence of any division. Computes the sum from 1 to n of ((10^prec) << 30) + 1)^2,
@@ -62,7 +61,7 @@
// Execute the above rep times, optionally timing it.
@Test
public void repeatInner() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 10; i <= 10_000; i *= 10) {
inner(100, i);
@@ -86,7 +85,7 @@
// Check results for equality, and print one, to compaare against reference.
@Test
public void repeatHarmonic1000() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 5; i <= 5_000; i *= 10) {
BigInteger refRes = harmonic1000(i);
@@ -107,7 +106,7 @@
// us to time and check it for consistency as well.
@Test
public void repeatToString() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 5; i <= 5_000; i *= 10) {
BigInteger refRes = harmonic1000(i);
@@ -147,7 +146,7 @@
// to compare to reference.
@Test
public void repeatEApprox() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 10; i <= 10_000; i *= 10) {
BigInteger refRes = eApprox(100_000, i);
@@ -166,7 +165,7 @@
// Test / time modPow()
@Test
public void repeatModPow() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 5; i <= 500; i *= 10) {
BigInteger odd1 = BigInteger.TEN.pow(i / 2).add(BigInteger.ONE);
@@ -199,7 +198,7 @@
// Test / time modInverse()
@Test
public void repeatModInverse() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 10; i <= 10_000; i *= 10) {
BigInteger odd1 = BigInteger.TEN.pow(i / 2).add(BigInteger.ONE);
diff --git a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
index 11ca73a..2a1b5d1 100644
--- a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
@@ -16,9 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
-
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -40,8 +39,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public final class BufferedZipFilePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
int[] mReadSize = new int[] {4, 32, 128};
int[] mCompressedSize = new int[] {128, 1024, 8192, 65536};
@@ -69,7 +67,7 @@
@Test
public void timeUnbufferedRead() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mCompressedSize.length; i++) {
for (int j = 0; j < mReadSize.length; j++) {
@@ -89,7 +87,7 @@
@Test
public void timeBufferedRead() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mCompressedSize.length; i++) {
for (int j = 0; j < mReadSize.length; j++) {
diff --git a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
index 0abe194..5f599ea 100644
--- a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,8 +30,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ClassLoaderResourcePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final String EXISTENT_RESOURCE = "java/util/logging/logging.properties";
private static final String MISSING_RESOURCE = "missing_entry";
@@ -41,7 +40,7 @@
ClassLoader currentClassLoader = getClass().getClassLoader();
Assert.assertNotNull(currentClassLoader.getResource(EXISTENT_RESOURCE));
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
currentClassLoader.getResource(EXISTENT_RESOURCE);
}
@@ -52,7 +51,7 @@
ClassLoader currentClassLoader = getClass().getClassLoader();
Assert.assertNull(currentClassLoader.getResource(MISSING_RESOURCE));
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
currentClassLoader.getResource(MISSING_RESOURCE);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
index 52441d1..ea24984 100644
--- a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,8 +29,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ClonePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static class CloneableObject implements Cloneable {
public Object clone() throws CloneNotSupportedException {
@@ -1128,7 +1127,7 @@
public void time_Object_clone() {
try {
CloneableObject o = new CloneableObject();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
o.clone();
}
@@ -1141,7 +1140,7 @@
public void time_Object_manyFieldClone() {
try {
CloneableManyFieldObject o = new CloneableManyFieldObject();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
o.clone();
}
@@ -1154,7 +1153,7 @@
public void time_Object_deepClone() {
try {
DeepCloneable o = new DeepCloneable();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
o.clone();
}
@@ -1166,7 +1165,7 @@
@Test
public void time_Array_clone() {
int[] o = new int[32];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
o.clone();
}
@@ -1178,7 +1177,7 @@
for (int i = 0; i < o.length / 2; ++i) {
o[i] = new Object();
}
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
o.clone();
}
@@ -1190,7 +1189,7 @@
for (int i = 0; i < o.length / 2; ++i) {
o[i] = new Object();
}
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
o.clone();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
index e6c5aca..82247dc 100644
--- a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -36,8 +36,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class DeepArrayOpsPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private Object[] mArray;
private Object[] mArray2;
@@ -100,7 +99,7 @@
@Parameters(method = "getData")
public void deepHashCode(int arrayLength) throws Exception {
setUp(arrayLength);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Arrays.deepHashCode(mArray);
}
@@ -110,7 +109,7 @@
@Parameters(method = "getData")
public void deepEquals(int arrayLength) throws Exception {
setUp(arrayLength);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Arrays.deepEquals(mArray, mArray2);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
index 378137b..0bebf04 100644
--- a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,8 +30,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class FieldAccessPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static class Inner {
public int mPublicInnerIntVal;
@@ -48,7 +47,7 @@
@Test
public void timeField() {
int result = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = mIntVal;
}
@@ -57,7 +56,7 @@
@Test
public void timeFieldFinal() {
int result = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = mFinalIntVal;
}
@@ -66,7 +65,7 @@
@Test
public void timeFieldStatic() {
int result = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = sStaticIntVal;
}
@@ -75,7 +74,7 @@
@Test
public void timeFieldStaticFinal() {
int result = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = FINAL_INT_VAL;
}
@@ -85,7 +84,7 @@
public void timeFieldCached() {
int result = 0;
int cachedIntVal = this.mIntVal;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = cachedIntVal;
}
@@ -95,7 +94,7 @@
public void timeFieldPrivateInnerClassPublicField() {
int result = 0;
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = inner.mPublicInnerIntVal;
}
@@ -105,7 +104,7 @@
public void timeFieldPrivateInnerClassProtectedField() {
int result = 0;
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = inner.mProtectedInnerIntVal;
}
@@ -115,7 +114,7 @@
public void timeFieldPrivateInnerClassPrivateField() {
int result = 0;
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = inner.mPrivateInnerIntVal;
}
@@ -125,7 +124,7 @@
public void timeFieldPrivateInnerClassPackageField() {
int result = 0;
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = inner.mPackageInnerIntVal;
}
diff --git a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
index 610e8e5..55c1027 100644
--- a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,14 +35,13 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class HashedCollectionsPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeHashMapGet() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("hello", "world");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
map.get("hello");
}
@@ -54,7 +53,7 @@
synchronized (map) {
map.put("hello", "world");
}
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
synchronized (map) {
map.get("hello");
@@ -66,7 +65,7 @@
public void timeHashtableGet() {
Hashtable<String, String> map = new Hashtable<String, String>();
map.put("hello", "world");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
map.get("hello");
}
@@ -76,7 +75,7 @@
public void timeLinkedHashMapGet() {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("hello", "world");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
map.get("hello");
}
@@ -86,7 +85,7 @@
public void timeConcurrentHashMapGet() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
map.put("hello", "world");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
map.get("hello");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
index 40c07e0..da60a77 100644
--- a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,8 +41,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ImtConflictPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Before
public void setup() {
@@ -281,7 +280,7 @@
@Test
public void timeConflictDepth01() {
C0 c0 = new C0();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c0);
callF0(c0);
@@ -309,7 +308,7 @@
@Test
public void timeConflictDepth02() {
C1 c1 = new C1();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c1);
callF19(c1);
@@ -337,7 +336,7 @@
@Test
public void timeConflictDepth03() {
C2 c2 = new C2();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c2);
callF19(c2);
@@ -365,7 +364,7 @@
@Test
public void timeConflictDepth04() {
C3 c3 = new C3();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c3);
callF19(c3);
@@ -393,7 +392,7 @@
@Test
public void timeConflictDepth05() {
C4 c4 = new C4();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c4);
callF19(c4);
@@ -421,7 +420,7 @@
@Test
public void timeConflictDepth06() {
C5 c5 = new C5();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c5);
callF19(c5);
@@ -449,7 +448,7 @@
@Test
public void timeConflictDepth07() {
C6 c6 = new C6();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c6);
callF19(c6);
@@ -477,7 +476,7 @@
@Test
public void timeConflictDepth08() {
C7 c7 = new C7();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c7);
callF19(c7);
@@ -505,7 +504,7 @@
@Test
public void timeConflictDepth09() {
C8 c8 = new C8();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c8);
callF19(c8);
@@ -533,7 +532,7 @@
@Test
public void timeConflictDepth10() {
C9 c9 = new C9();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c9);
callF19(c9);
@@ -561,7 +560,7 @@
@Test
public void timeConflictDepth11() {
C10 c10 = new C10();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c10);
callF19(c10);
@@ -589,7 +588,7 @@
@Test
public void timeConflictDepth12() {
C11 c11 = new C11();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c11);
callF19(c11);
@@ -617,7 +616,7 @@
@Test
public void timeConflictDepth13() {
C12 c12 = new C12();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c12);
callF19(c12);
@@ -645,7 +644,7 @@
@Test
public void timeConflictDepth14() {
C13 c13 = new C13();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c13);
callF19(c13);
@@ -673,7 +672,7 @@
@Test
public void timeConflictDepth15() {
C14 c14 = new C14();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c14);
callF19(c14);
@@ -701,7 +700,7 @@
@Test
public void timeConflictDepth16() {
C15 c15 = new C15();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c15);
callF19(c15);
@@ -729,7 +728,7 @@
@Test
public void timeConflictDepth17() {
C16 c16 = new C16();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c16);
callF19(c16);
@@ -757,7 +756,7 @@
@Test
public void timeConflictDepth18() {
C17 c17 = new C17();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c17);
callF19(c17);
@@ -785,7 +784,7 @@
@Test
public void timeConflictDepth19() {
C18 c18 = new C18();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c18);
callF19(c18);
@@ -813,7 +812,7 @@
@Test
public void timeConflictDepth20() {
C19 c19 = new C19();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
callF0(c19);
callF19(c19);
diff --git a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
index e1d0bf2..6d9d0c9 100644
--- a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,8 +30,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MethodInvocationPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
interface I {
void emptyInterface();
@@ -66,12 +65,12 @@
}
public void timeInternalGetter() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
new C().timeInternalGetter(state);
}
public void timeInternalFieldAccess() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
new C().timeInternalFieldAccess(state);
}
@@ -79,7 +78,7 @@
@Test
public void timeStringLength() {
int result = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = "hello, world!".length();
}
@@ -88,7 +87,7 @@
@Test
public void timeEmptyStatic() {
C c = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
c.emptyStatic();
}
@@ -97,7 +96,7 @@
@Test
public void timeEmptyVirtual() {
C c = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
c.emptyVirtual();
}
@@ -106,7 +105,7 @@
@Test
public void timeEmptyInterface() {
I c = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
c.emptyInterface();
}
@@ -139,7 +138,7 @@
@Test
public void timePrivateInnerPublicMethod() {
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
inner.publicMethod();
}
@@ -148,7 +147,7 @@
@Test
public void timePrivateInnerProtectedMethod() {
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
inner.protectedMethod();
}
@@ -157,7 +156,7 @@
@Test
public void timePrivateInnerPrivateMethod() {
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
inner.privateMethod();
}
@@ -166,7 +165,7 @@
@Test
public void timePrivateInnerPackageMethod() {
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
inner.packageMethod();
}
@@ -175,7 +174,7 @@
@Test
public void timePrivateInnerFinalPackageMethod() {
Inner inner = new Inner();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
inner.finalPackageMethod();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
index c5e9d1e..09b0977 100644
--- a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,13 +30,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MultiplicationPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeMultiplyIntByConstant10() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 10;
}
@@ -45,7 +44,7 @@
@Test
public void timeMultiplyIntByConstant8() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 8;
}
@@ -55,7 +54,7 @@
public void timeMultiplyIntByVariable10() {
int result = 1;
int factor = 10;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= factor;
}
@@ -65,7 +64,7 @@
public void timeMultiplyIntByVariable8() {
int result = 1;
int factor = 8;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= factor;
}
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
index d073f91..ba21ed3 100644
--- a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,8 +35,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReferenceGetPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
boolean mIntrinsicDisabled;
@@ -52,7 +51,7 @@
@Test
public void timeSoftReferenceGet() throws Exception {
Reference soft = new SoftReference(mObj);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Object o = soft.get();
}
@@ -61,7 +60,7 @@
@Test
public void timeWeakReferenceGet() throws Exception {
Reference weak = new WeakReference(mObj);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Object o = weak.get();
}
@@ -72,7 +71,7 @@
Reference weak = new WeakReference(mObj);
mObj = null;
Runtime.getRuntime().gc();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Object o = weak.get();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
index af13773..293752e 100644
--- a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,8 +34,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReferencePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private Object mObject;
@@ -43,7 +42,7 @@
@Test
public void timeAlloc() {
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new PhantomReference(mObject, queue);
}
@@ -53,7 +52,7 @@
@Test
public void timeAllocAndEnqueue() {
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
(new PhantomReference<Object>(mObject, queue)).enqueue();
}
@@ -63,7 +62,7 @@
@Test
public void timeAllocEnqueueAndPoll() {
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
(new PhantomReference<Object>(mObject, queue)).enqueue();
queue.poll();
@@ -74,7 +73,7 @@
@Test
public void timeAllocEnqueueAndRemove() {
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
(new PhantomReference<Object>(mObject, queue)).enqueue();
try {
@@ -103,7 +102,7 @@
// Allocate a bunch of finalizable objects.
int n = 0;
AtomicInteger count = new AtomicInteger(0);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
n++;
new FinalizableObject(count);
diff --git a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
index cf573fa..528b751 100644
--- a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,9 +41,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SmallBigIntegerPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
-
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
// We allocate about 2 1/3 BigIntegers per iteration.
// Assuming 100 bytes/BigInteger, this gives us around 500MB total.
static final BigInteger BIG_THREE = BigInteger.valueOf(3);
@@ -53,7 +51,7 @@
public void testSmallBigInteger() {
final Random r = new Random();
BigInteger x = new BigInteger(20, r);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
// We know this converges, but the compiler doesn't.
if (x.and(BigInteger.ONE).equals(BigInteger.ONE)) {
diff --git a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
index d28154c..1f301ac 100644
--- a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,14 +30,13 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringDexCachePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeStringDexCacheAccess() {
int v = 0;
int count = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
// Deliberately obscured to make optimizations less likely.
String s = (count >= 0) ? "hello, world!" : null;
diff --git a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
index 40a8db0..4268325 100644
--- a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,13 +30,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringIterationPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeStringIteration0() {
String s = "hello, world!";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
char ch;
for (int i = 0; i < s.length(); ++i) {
@@ -48,7 +47,7 @@
@Test
public void timeStringIteration1() {
String s = "hello, world!";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
char ch;
for (int i = 0, length = s.length(); i < length; ++i) {
@@ -60,7 +59,7 @@
@Test
public void timeStringIteration2() {
String s = "hello, world!";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
char ch;
char[] chars = s.toCharArray();
@@ -73,7 +72,7 @@
@Test
public void timeStringToCharArray() {
String s = "hello, world!";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
char[] chars = s.toCharArray();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
index 147ea50..cb3d3ac 100644
--- a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -36,13 +36,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VirtualVersusInterfacePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeMapPut() {
Map<String, String> map = new HashMap<String, String>();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
map.put("hello", "world");
}
@@ -51,7 +50,7 @@
@Test
public void timeHashMapPut() {
HashMap<String, String> map = new HashMap<String, String>();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
map.put("hello", "world");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
index bb1c298..5be8ee6 100644
--- a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -36,8 +36,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class XmlSerializePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private Object[] getParams() {
return new Object[][] {
@@ -109,7 +108,7 @@
private void internalTimeSerializer(Constructor<? extends XmlSerializer> ctor, int seed)
throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
serializeRandomXml(ctor, seed);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
index 9360a25..a37b89d 100644
--- a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import android.util.Xml;
import androidx.test.filters.LargeTest;
@@ -44,11 +44,11 @@
public class XmlSerializerPerfTest {
@Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeFastSerializer_nonIndent_depth100() throws IOException {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
XmlSerializer serializer = Xml.newFastSerializer();
runTest(serializer, 100);
@@ -57,7 +57,7 @@
@Test
public void timeFastSerializer_indent_depth100() throws IOException {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
XmlSerializer serializer = Xml.newFastSerializer();
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
@@ -67,7 +67,7 @@
@Test
public void timeKXmlSerializer_nonIndent_depth100() throws IOException {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
XmlSerializer serializer = XmlObjectFactory.newXmlSerializer();
runTest(serializer, 100);
@@ -76,7 +76,7 @@
@Test
public void timeKXmlSerializer_indent_depth100() throws IOException {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
XmlSerializer serializer = XmlObjectFactory.newXmlSerializer();
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index 03f183a..ed669be 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -42,8 +42,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class ZipFilePerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private File mFile;
@@ -66,7 +65,7 @@
@Parameters(method = "getData")
public void timeZipFileOpen(int numEntries) throws Exception {
setUp(numEntries);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ZipFile zf = new ZipFile(mFile);
state.pauseTiming();
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
index 3614061..d239a05 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -44,8 +44,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class ZipFileReadPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(new Object[][] {{1024}, {16384}, {65536}});
@@ -92,7 +91,7 @@
@Parameters(method = "getData")
public void timeZipFileRead(int readBufferSize) throws Exception {
byte[] readBuffer = new byte[readBufferSize];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ZipFile zipFile = new ZipFile(mFile);
for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
index 8890f51..487295c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,8 +35,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class AnnotatedElementPerfTest {
- @Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private Class<?> mType;
private Field mField;
@@ -53,7 +52,7 @@
@Test
public void timeGetTypeAnnotations() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mType.getAnnotations();
}
@@ -61,7 +60,7 @@
@Test
public void timeGetFieldAnnotations() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.getAnnotations();
}
@@ -69,7 +68,7 @@
@Test
public void timeGetMethodAnnotations() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mMethod.getAnnotations();
}
@@ -77,7 +76,7 @@
@Test
public void timeGetParameterAnnotations() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mMethod.getParameterAnnotations();
}
@@ -85,7 +84,7 @@
@Test
public void timeGetTypeAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mType.getAnnotation(Marker.class);
}
@@ -93,7 +92,7 @@
@Test
public void timeGetFieldAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.getAnnotation(Marker.class);
}
@@ -101,7 +100,7 @@
@Test
public void timeGetMethodAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mMethod.getAnnotation(Marker.class);
}
@@ -109,7 +108,7 @@
@Test
public void timeIsTypeAnnotationPresent() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mType.isAnnotationPresent(Marker.class);
}
@@ -117,7 +116,7 @@
@Test
public void timeIsFieldAnnotationPresent() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.isAnnotationPresent(Marker.class);
}
@@ -125,7 +124,7 @@
@Test
public void timeIsMethodAnnotationPresent() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mMethod.isAnnotationPresent(Marker.class);
}
@@ -135,7 +134,7 @@
@Test
public void timeGetAllReturnsLargeAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasLargeAnnotation.class.getAnnotations();
}
@@ -143,7 +142,7 @@
@Test
public void timeGetAllReturnsSmallAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasSmallAnnotation.class.getAnnotations();
}
@@ -151,7 +150,7 @@
@Test
public void timeGetAllReturnsMarkerAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasMarkerAnnotation.class.getAnnotations();
}
@@ -159,7 +158,7 @@
@Test
public void timeGetAllReturnsNoAnnotation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasNoAnnotations.class.getAnnotations();
}
@@ -167,7 +166,7 @@
@Test
public void timeGetAllReturnsThreeAnnotations() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasThreeAnnotations.class.getAnnotations();
}
@@ -177,7 +176,7 @@
@Test
public void timeGetAnnotationsOnSubclass() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ExtendsHasThreeAnnotations.class.getAnnotations();
}
@@ -185,7 +184,7 @@
@Test
public void timeGetDeclaredAnnotationsOnSubclass() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ExtendsHasThreeAnnotations.class.getDeclaredAnnotations();
}
@@ -195,7 +194,7 @@
@Test
public void timeGetDeclaredClasses() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
AnnotatedElementPerfTest.class.getDeclaredClasses();
}
@@ -203,7 +202,7 @@
@Test
public void timeGetDeclaringClass() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasSmallAnnotation.class.getDeclaringClass();
}
@@ -212,7 +211,7 @@
@Test
public void timeGetEnclosingClass() {
Object anonymousClass = new Object() {};
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
anonymousClass.getClass().getEnclosingClass();
}
@@ -221,7 +220,7 @@
@Test
public void timeGetEnclosingConstructor() {
Object anonymousClass = new Object() {};
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
anonymousClass.getClass().getEnclosingConstructor();
}
@@ -230,7 +229,7 @@
@Test
public void timeGetEnclosingMethod() {
Object anonymousClass = new Object() {};
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
anonymousClass.getClass().getEnclosingMethod();
}
@@ -238,7 +237,7 @@
@Test
public void timeGetModifiers() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasSmallAnnotation.class.getModifiers();
}
@@ -246,7 +245,7 @@
@Test
public void timeGetSimpleName() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasSmallAnnotation.class.getSimpleName();
}
@@ -255,7 +254,7 @@
@Test
public void timeIsAnonymousClass() {
Object anonymousClass = new Object() {};
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
anonymousClass.getClass().isAnonymousClass();
}
@@ -263,7 +262,7 @@
@Test
public void timeIsLocalClass() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
HasSmallAnnotation.class.isLocalClass();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
index baab860..adc5d8c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,14 +34,14 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class BidiPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final AttributedCharacterIterator CHAR_ITER =
DecimalFormat.getInstance().formatToCharacterIterator(new BigDecimal(Math.PI));
@Test
public void time_createBidiFromIter() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi bidi = new Bidi(CHAR_ITER);
}
@@ -49,7 +49,7 @@
@Test
public void time_createBidiFromCharArray() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi bd =
new Bidi(
@@ -64,7 +64,7 @@
@Test
public void time_createBidiFromString() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi bidi = new Bidi("Hello", Bidi.DIRECTION_LEFT_TO_RIGHT);
}
@@ -72,7 +72,7 @@
@Test
public void time_reorderVisually() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi.reorderVisually(
new byte[] {2, 1, 3, 0, 4}, 0, new String[] {"H", "e", "l", "l", "o"}, 0, 5);
@@ -81,7 +81,7 @@
@Test
public void time_hebrewBidi() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi bd =
new Bidi(
@@ -104,7 +104,7 @@
@Test
public void time_complicatedOverrideBidi() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi bd =
new Bidi(
@@ -119,7 +119,7 @@
@Test
public void time_requiresBidi() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Bidi.requiresBidi("\u05D0".toCharArray(), 1, 1); // false.
Bidi.requiresBidi("\u05D0".toCharArray(), 0, 1); // true.
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
index 8a539f8..286d703 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,14 +32,14 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class BigIntegerPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeRandomDivision() throws Exception {
Random r = new Random();
BigInteger x = new BigInteger(1024, r);
BigInteger y = new BigInteger(1024, r);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x.divide(y);
}
@@ -50,7 +50,7 @@
Random r = new Random();
BigInteger x = new BigInteger(1024, r);
BigInteger y = new BigInteger(1024, r);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x.gcd(y);
}
@@ -61,7 +61,7 @@
Random r = new Random();
BigInteger x = new BigInteger(1024, r);
BigInteger y = new BigInteger(1024, r);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x.multiply(y);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
index 1b46ff4..d646202 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -35,7 +35,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class BitSetPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(new Object[][] {{1000}, {10000}});
@@ -45,7 +45,7 @@
@Parameters(method = "getData")
public void timeIsEmptyTrue(int size) {
BitSet bitSet = new BitSet(size);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
if (!bitSet.isEmpty()) throw new RuntimeException();
}
@@ -56,7 +56,7 @@
public void timeIsEmptyFalse(int size) {
BitSet bitSet = new BitSet(size);
bitSet.set(bitSet.size() - 1);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
if (bitSet.isEmpty()) throw new RuntimeException();
}
@@ -66,7 +66,7 @@
@Parameters(method = "getData")
public void timeGet(int size) {
BitSet bitSet = new BitSet(size);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int i = 1;
while (state.keepRunning()) {
bitSet.get(++i % size);
@@ -77,7 +77,7 @@
@Parameters(method = "getData")
public void timeClear(int size) {
BitSet bitSet = new BitSet(size);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int i = 1;
while (state.keepRunning()) {
bitSet.clear(++i % size);
@@ -89,7 +89,7 @@
public void timeSet(int size) {
BitSet bitSet = new BitSet(size);
int i = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
bitSet.set(++i % size);
}
@@ -100,7 +100,7 @@
public void timeSetOn(int size) {
BitSet bitSet = new BitSet(size);
int i = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
bitSet.set(++i % size, true);
}
@@ -111,7 +111,7 @@
public void timeSetOff(int size) {
BitSet bitSet = new BitSet(size);
int i = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
bitSet.set(++i % size, false);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
index 3c5e4fd..b887f40 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -36,7 +36,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class BreakIteratorPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public enum Text {
LIPSUM(
@@ -165,7 +165,7 @@
@Test
@Parameters(method = "getData")
public void timeBreakIterator(Text text) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
BreakIterator it = BreakIterator.getLineInstance(text.mLocale);
it.setText(text.mText);
@@ -179,7 +179,7 @@
@Test
@Parameters(method = "getData")
public void timeIcuBreakIterator(Text text) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
android.icu.text.BreakIterator it =
android.icu.text.BreakIterator.getLineInstance(text.mLocale);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
index 6df67bc..e4eaf12 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -39,7 +39,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class BulkPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -120,7 +120,7 @@
throws Exception {
ByteBuffer src = BulkPerfTest.newBuffer(align, sBuf, size);
ByteBuffer data = BulkPerfTest.newBuffer(align, dBuf, size);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(align ? 0 : 1);
data.position(align ? 0 : 1);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
index f01ac02..42e3910a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -46,7 +46,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class ByteBufferPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public enum MyByteOrder {
BIG(ByteOrder.BIG_ENDIAN),
@@ -121,7 +121,7 @@
public void timeByteBuffer_getByte(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -136,7 +136,7 @@
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
byte[] dst = new byte[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(aligned ? 0 : 1);
@@ -150,7 +150,7 @@
public void timeByteBuffer_getByte_indexed(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -164,7 +164,7 @@
public void timeByteBuffer_getChar(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -180,7 +180,7 @@
CharBuffer src =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asCharBuffer();
char[] dst = new char[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(0);
@@ -194,7 +194,7 @@
public void timeByteBuffer_getChar_indexed(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -208,7 +208,7 @@
public void timeByteBuffer_getDouble(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -224,7 +224,7 @@
DoubleBuffer src =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asDoubleBuffer();
double[] dst = new double[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(0);
@@ -238,7 +238,7 @@
public void timeByteBuffer_getFloat(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -254,7 +254,7 @@
FloatBuffer src =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asFloatBuffer();
float[] dst = new float[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(0);
@@ -268,7 +268,7 @@
public void timeByteBuffer_getInt(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -283,7 +283,7 @@
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
IntBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asIntBuffer();
int[] dst = new int[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(0);
@@ -297,7 +297,7 @@
public void timeByteBuffer_getLong(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -313,7 +313,7 @@
LongBuffer src =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asLongBuffer();
long[] dst = new long[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(0);
@@ -327,7 +327,7 @@
public void timeByteBuffer_getShort(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -343,7 +343,7 @@
ShortBuffer src =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asShortBuffer();
short[] dst = new short[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
src.position(0);
@@ -361,7 +361,7 @@
public void timeByteBuffer_putByte(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(0);
for (int i = 0; i < 1024; ++i) {
@@ -376,7 +376,7 @@
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
byte[] src = new byte[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(aligned ? 0 : 1);
@@ -390,7 +390,7 @@
public void timeByteBuffer_putChar(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -406,7 +406,7 @@
CharBuffer dst =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asCharBuffer();
char[] src = new char[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(0);
@@ -420,7 +420,7 @@
public void timeByteBuffer_putDouble(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -436,7 +436,7 @@
DoubleBuffer dst =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asDoubleBuffer();
double[] src = new double[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(0);
@@ -450,7 +450,7 @@
public void timeByteBuffer_putFloat(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -466,7 +466,7 @@
FloatBuffer dst =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asFloatBuffer();
float[] src = new float[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(0);
@@ -480,7 +480,7 @@
public void timeByteBuffer_putInt(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -495,7 +495,7 @@
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
IntBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asIntBuffer();
int[] src = new int[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(0);
@@ -509,7 +509,7 @@
public void timeByteBuffer_putLong(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -525,7 +525,7 @@
LongBuffer dst =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asLongBuffer();
long[] src = new long[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(0);
@@ -539,7 +539,7 @@
public void timeByteBuffer_putShort(
MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
for (int i = 0; i < 1024; ++i) {
@@ -555,7 +555,7 @@
ShortBuffer dst =
ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asShortBuffer();
short[] src = new short[1024];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < 1024; ++i) {
dst.position(0);
@@ -566,7 +566,7 @@
@Test
public void time_new_byteArray() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
byte[] bs = new byte[8192];
}
@@ -574,7 +574,7 @@
@Test
public void time_ByteBuffer_allocate() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ByteBuffer bs = ByteBuffer.allocate(8192);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
index 8c318cd..9ee927c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -35,7 +35,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class ByteBufferScalarVersusVectorPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -112,7 +112,7 @@
throws Exception {
ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
ByteBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(0);
dst.position(0);
@@ -127,7 +127,7 @@
public void timeByteBufferBulkGet(boolean aligned) throws Exception {
ByteBuffer src = ByteBuffer.allocate(aligned ? 8192 : 8192 + 1);
byte[] dst = new byte[8192];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
src.get(dst, 0, dst.length);
@@ -139,7 +139,7 @@
public void timeDirectByteBufferBulkGet(boolean aligned) throws Exception {
ByteBuffer src = ByteBuffer.allocateDirect(aligned ? 8192 : 8192 + 1);
byte[] dst = new byte[8192];
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
src.position(aligned ? 0 : 1);
src.get(dst, 0, dst.length);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
index 12c1f8c..e4a4db7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -38,7 +38,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class CharacterPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -84,7 +84,7 @@
public void timeIsSpace(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
boolean fake = false;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -104,7 +104,7 @@
@Parameters(method = "getData")
public void timeDigit(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -124,7 +124,7 @@
@Parameters(method = "getData")
public void timeGetNumericValue(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -144,7 +144,7 @@
@Parameters(method = "getData")
public void timeIsDigit(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -164,7 +164,7 @@
@Parameters(method = "getData")
public void timeIsIdentifierIgnorable(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -184,7 +184,7 @@
@Parameters(method = "getData")
public void timeIsJavaIdentifierPart(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -204,7 +204,7 @@
@Parameters(method = "getData")
public void timeIsJavaIdentifierStart(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -224,7 +224,7 @@
@Parameters(method = "getData")
public void timeIsLetter(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -244,7 +244,7 @@
@Parameters(method = "getData")
public void timeIsLetterOrDigit(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -264,7 +264,7 @@
@Parameters(method = "getData")
public void timeIsLowerCase(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -284,7 +284,7 @@
@Parameters(method = "getData")
public void timeIsSpaceChar(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -304,7 +304,7 @@
@Parameters(method = "getData")
public void timeIsUpperCase(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -324,7 +324,7 @@
@Parameters(method = "getData")
public void timeIsWhitespace(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -344,7 +344,7 @@
@Parameters(method = "getData")
public void timeToLowerCase(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
@@ -364,7 +364,7 @@
@Parameters(method = "getData")
public void timeToUpperCase(CharacterSet characterSet, Overload overload) {
setUp(characterSet);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
if (overload == Overload.CHAR) {
while (state.keepRunning()) {
for (int ch = 0; ch < 65536; ++ch) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
index 4dd890a..858c101 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -33,7 +33,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class CharsetForNamePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static String[] charsetNames() {
return new String[] {
@@ -52,7 +52,7 @@
@Test
@Parameters(method = "charsetNames")
public void timeCharsetForName(String charsetName) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Charset.forName(charsetName);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
index 3a71ce9..a2fb7d7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -34,7 +34,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class CharsetPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -91,7 +91,7 @@
@Parameters(method = "getData")
public void time_new_String_BString(int length, String name) throws Exception {
byte[] bytes = makeBytes(makeString(length));
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new String(bytes, name);
}
@@ -101,7 +101,7 @@
@Parameters(method = "getData")
public void time_new_String_BII(int length, String name) throws Exception {
byte[] bytes = makeBytes(makeString(length));
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new String(bytes, 0, bytes.length);
}
@@ -111,7 +111,7 @@
@Parameters(method = "getData")
public void time_new_String_BIIString(int length, String name) throws Exception {
byte[] bytes = makeBytes(makeString(length));
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new String(bytes, 0, bytes.length, name);
}
@@ -121,7 +121,7 @@
@Parameters(method = "getData")
public void time_String_getBytes(int length, String name) throws Exception {
String string = makeString(length);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
string.getBytes(name);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
index 6c30a16..2047444 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
import android.icu.lang.UCharacter;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,7 +35,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class CharsetUtf8PerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private void makeUnicodeRange(int startingCodePoint, int endingCodePoint) {
StringBuilder builder = new StringBuilder();
@@ -46,7 +46,7 @@
}
String str = builder.toString();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder builder2 = new StringBuilder();
builder2.append(str);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
index dcdfd37..4ce8b41 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,13 +32,13 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ChecksumPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeAdler_block() throws Exception {
byte[] bytes = new byte[10000];
Adler32 adler = new Adler32();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
adler.update(bytes);
}
@@ -47,7 +47,7 @@
@Test
public void timeAdler_byte() throws Exception {
Adler32 adler = new Adler32();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
adler.update(1);
}
@@ -57,7 +57,7 @@
public void timeCrc_block() throws Exception {
byte[] bytes = new byte[10000];
CRC32 crc = new CRC32();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
crc.update(bytes);
}
@@ -66,7 +66,7 @@
@Test
public void timeCrc_byte() throws Exception {
CRC32 crc = new CRC32();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
crc.update(1);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
index 6c175b1..6a7ec1a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,7 +41,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class CipherInputStreamPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final int DATA_SIZE = 1024 * 1024;
private static final byte[] DATA = new byte[DATA_SIZE];
@@ -80,7 +80,7 @@
@Test
public void timeEncrypt() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
InputStream is = new CipherInputStream(new ByteArrayInputStream(DATA), mCipherEncrypt);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
index 136822e..238c028 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -47,7 +47,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class CipherPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection getCases() {
int[] keySizes = new int[] {128, 192, 256};
@@ -180,7 +180,7 @@
Mode mode, Padding padding, int keySize, int inputSize, Implementation implementation)
throws Exception {
setUp(mode, padding, keySize, implementation);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mCipherEncrypt.doFinal(DATA, 0, inputSize, mOutput);
}
@@ -192,7 +192,7 @@
Mode mode, Padding padding, int keySize, int inputSize, Implementation implementation)
throws Exception {
setUp(mode, padding, keySize, implementation);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mCipherDecrypt.doFinal(DATA, 0, inputSize, mOutput);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
index 9efb7ce..7e55660 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class CollatorPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final RuleBasedCollator COLLATOR =
(RuleBasedCollator) Collator.getInstance(Locale.US);
@@ -41,7 +41,7 @@
@Test
public void timeCollatorPrimary() {
COLLATOR.setStrength(Collator.PRIMARY);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
COLLATOR.compare("abcde", "abcdf");
COLLATOR.compare("abcde", "abcde");
@@ -52,7 +52,7 @@
@Test
public void timeCollatorSecondary() {
COLLATOR.setStrength(Collator.SECONDARY);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
COLLATOR.compare("abcdÂ", "abcdÄ");
COLLATOR.compare("abcdÂ", "abcdÂ");
@@ -63,7 +63,7 @@
@Test
public void timeCollatorTertiary() {
COLLATOR.setStrength(Collator.TERTIARY);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
COLLATOR.compare("abcdE", "abcde");
COLLATOR.compare("abcde", "abcde");
@@ -74,7 +74,7 @@
@Test
public void timeCollatorIdentical() {
COLLATOR.setStrength(Collator.IDENTICAL);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
COLLATOR.compare("abcdȪ", "abcdȫ");
COLLATOR.compare("abcdȪ", "abcdȪ");
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
index 4e5ceaf..100798a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -40,7 +40,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class CollectionsPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(new Object[][] {{4}, {16}, {64}, {256}, {1024}});
@@ -60,7 +60,7 @@
@Parameters(method = "getData")
public void timeSort_arrayList(int arrayListLength) throws Exception {
List<Integer> input = buildList(arrayListLength, ArrayList.class);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Collections.sort(input);
}
@@ -70,7 +70,7 @@
@Parameters(method = "getData")
public void timeSortWithComparator_arrayList(int arrayListLength) throws Exception {
List<Integer> input = buildList(arrayListLength, ArrayList.class);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Collections.sort(input, REVERSE);
}
@@ -80,7 +80,7 @@
@Parameters(method = "getData")
public void timeSort_vector(int arrayListLength) throws Exception {
List<Integer> input = buildList(arrayListLength, Vector.class);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Collections.sort(input);
}
@@ -90,7 +90,7 @@
@Parameters(method = "getData")
public void timeSortWithComparator_vector(int arrayListLength) throws Exception {
List<Integer> input = buildList(arrayListLength, Vector.class);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Collections.sort(input, REVERSE);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
index b0ccd99..b6784a8 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public final class DateFormatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private Locale mLocale1;
private Locale mLocale2;
@@ -50,7 +50,7 @@
@Test
public void timeGetDateTimeInstance() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DateFormat.getDateTimeInstance();
}
@@ -58,7 +58,7 @@
@Test
public void timeGetDateTimeInstance_multiple() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale1);
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale2);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
index 3a2f6fa..52f9873 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,7 +34,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DecimalFormatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final String EXP_PATTERN = "##E0";
@@ -58,7 +58,7 @@
public void formatWithGrouping(Object obj) {
DF.setGroupingSize(3);
DF.setGroupingUsed(true);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DF.format(obj);
}
@@ -66,21 +66,21 @@
public void format(String pattern, Object obj) {
PATTERN_INSTANCE.applyPattern(pattern);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
PATTERN_INSTANCE.format(obj);
}
}
public void format(Object obj) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DF.format(obj);
}
}
public void formatToCharacterIterator(Object obj) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DF.formatToCharacterIterator(obj);
}
@@ -88,14 +88,14 @@
public void formatCurrencyUS(Object obj) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DF_CURRENCY_US.format(obj);
}
}
public void formatCurrencyFR(Object obj) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DF_CURRENCY_FR.format(obj);
}
@@ -213,7 +213,7 @@
@Test
public void time_instantiation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new DecimalFormat();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
index 4bc550e..6105420 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
@@ -15,8 +15,8 @@
*/
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,13 +31,13 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DecimalFormatSymbolsPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static Locale sLocale = Locale.getDefault(Locale.Category.FORMAT);
@Test
public void time_instantiation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new DecimalFormatSymbols(sLocale);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
index 597447b..fae74a5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DefaultCharsetPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void time_defaultCharset() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Charset.defaultCharset();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
index b17d0f4..2915363 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DnsPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeDns() throws Exception {
@@ -53,7 +53,7 @@
"www.cnn.com",
"bad.host.mtv.corp.google.com",
};
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int i = 0;
while (state.keepRunning()) {
try {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
index 4c8a8ea..dd7e5cc 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,11 +32,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DoPrivilegedPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeDirect() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String lineSeparator = System.getProperty("line.separator");
}
@@ -44,7 +44,7 @@
@Test
public void timeFastAndSlow() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String lineSeparator;
if (System.getSecurityManager() == null) {
@@ -61,7 +61,7 @@
@Test
public void timeNewAction() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String lineSeparator = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
@@ -74,7 +74,7 @@
@Test
public void timeReusedAction() throws Exception {
final PrivilegedAction<String> action = new ReusableAction("line.separator");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String lineSeparator = AccessController.doPrivileged(action);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
index 4ff65b1..e034a47 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DoublePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private double mD = 1.2;
private long mL = 4608083138725491507L;
@@ -37,7 +37,7 @@
@Test
public void timeDoubleToLongBits() {
long result = 123;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Double.doubleToLongBits(mD);
}
@@ -49,7 +49,7 @@
@Test
public void timeDoubleToRawLongBits() {
long result = 123;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Double.doubleToRawLongBits(mD);
}
@@ -61,7 +61,7 @@
@Test
public void timeLongBitsToDouble() {
double result = 123.0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Double.longBitsToDouble(mL);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
index aacdcee1..fe1b599 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -37,7 +37,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class EqualsHashCodePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private enum Type {
URI() {
@@ -82,7 +82,7 @@
mA2 = type.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox");
mB1 = type.newInstance("http://developer.android.com/reference/java/net/URI.html");
mB2 = type.newInstance("http://developer.android.com/reference/java/net/URI.html");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mA1.equals(mB1);
mA1.equals(mA2);
@@ -95,7 +95,7 @@
public void timeHashCode(Type type) throws Exception {
mA1 = type.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox");
mB1 = type.newInstance("http://developer.android.com/reference/java/net/URI.html");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mA1.hashCode();
mB1.hashCode();
@@ -112,7 +112,7 @@
"http://developer.android.com/query?q="
+ QUERY.substring(0, QUERY.length() - 3)
+ "%AF");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mC1.equals(mC2);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index 9a6864e..ecbfc71 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,11 +41,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ExpensiveObjectsPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeNewDateFormatTimeInstance() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
df.format(System.currentTimeMillis());
@@ -55,7 +55,7 @@
@Test(timeout = 900000)
public void timeClonedDateFormatTimeInstance() {
DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
((DateFormat) df.clone()).format(System.currentTimeMillis());
}
@@ -64,7 +64,7 @@
@Test
public void timeReusedDateFormatTimeInstance() {
DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
synchronized (df) {
df.format(System.currentTimeMillis());
@@ -74,7 +74,7 @@
@Test(timeout = 900000)
public void timeNewCollator() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Collator.getInstance(Locale.US);
}
@@ -83,7 +83,7 @@
@Test
public void timeClonedCollator() {
Collator c = Collator.getInstance(Locale.US);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
c.clone();
}
@@ -91,7 +91,7 @@
@Test
public void timeNewDateFormatSymbols() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new DateFormatSymbols(Locale.US);
}
@@ -100,7 +100,7 @@
@Test
public void timeClonedDateFormatSymbols() {
DateFormatSymbols dfs = new DateFormatSymbols(Locale.US);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
dfs.clone();
}
@@ -108,7 +108,7 @@
@Test
public void timeNewDecimalFormatSymbols() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new DecimalFormatSymbols(Locale.US);
}
@@ -117,7 +117,7 @@
@Test
public void timeClonedDecimalFormatSymbols() {
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
dfs.clone();
}
@@ -125,7 +125,7 @@
@Test
public void timeNewNumberFormat() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
NumberFormat.getInstance(Locale.US);
}
@@ -134,7 +134,7 @@
@Test
public void timeClonedNumberFormat() {
NumberFormat nf = NumberFormat.getInstance(Locale.US);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
nf.clone();
}
@@ -142,7 +142,7 @@
@Test
public void timeLongToString() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Long.toString(1024L);
}
@@ -151,7 +151,7 @@
@Test
public void timeNumberFormatTrivialFormatDouble() {
NumberFormat nf = NumberFormat.getInstance(Locale.US);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
nf.format(1024.0);
}
@@ -159,7 +159,7 @@
@Test
public void timeNewSimpleDateFormat() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new SimpleDateFormat();
}
@@ -167,7 +167,7 @@
@Test
public void timeNewGregorianCalendar() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new GregorianCalendar();
}
@@ -176,7 +176,7 @@
@Test
public void timeClonedGregorianCalendar() {
GregorianCalendar gc = new GregorianCalendar();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
gc.clone();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
index cef7e8c7..0c14d64 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public final class FilePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeFileCreationWithEmptyChild() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new File("/foo", "/");
}
@@ -43,7 +43,7 @@
@Test
public void timeFileCreationWithNormalizationNecessary() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new File("/foo//bar//baz//bag", "/baz/");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
index 645c023..7d7d83b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class FloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private float mFloat = 1.2f;
private int mInt = 1067030938;
@@ -37,7 +37,7 @@
@Test
public void timeFloatToIntBits() {
int result = 123;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Float.floatToIntBits(mFloat);
}
@@ -49,7 +49,7 @@
@Test
public void timeFloatToRawIntBits() {
int result = 123;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Float.floatToRawIntBits(mFloat);
}
@@ -61,7 +61,7 @@
@Test
public void timeIntBitsToFloat() {
float result = 123.0f;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Float.intBitsToFloat(mInt);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
index cf76137..08dda53 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,11 +35,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class FormatterPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeFormatter_NoFormatting() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a reasonably short string that doesn't actually need any formatting");
@@ -48,7 +48,7 @@
@Test
public void timeStringBuilder_NoFormatting() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
sb.append("this is a reasonably short string that doesn't actually need formatting");
@@ -58,7 +58,7 @@
@Test
public void timeFormatter_OneInt() {
Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a reasonably short string that has an int %d in it", value);
@@ -69,7 +69,7 @@
public void timeFormatter_OneIntArabic() {
Locale arabic = new Locale("ar");
Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format(arabic, "this is a reasonably short string that has an int %d in it", value);
@@ -78,7 +78,7 @@
@Test
public void timeStringBuilder_OneInt() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
sb.append("this is a reasonably short string that has an int ");
@@ -90,7 +90,7 @@
@Test
public void timeFormatter_OneHexInt() {
Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a reasonably short string that has an int %x in it", value);
@@ -99,7 +99,7 @@
@Test
public void timeStringBuilder_OneHexInt() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
sb.append("this is a reasonably short string that has an int ");
@@ -111,7 +111,7 @@
@Test
public void timeFormatter_OneFloat() {
Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a reasonably short string that has a float %f in it", value);
@@ -121,7 +121,7 @@
@Test
public void timeFormatter_OneFloat_dot2f() {
Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a reasonably short string that has a float %.2f in it", value);
@@ -131,7 +131,7 @@
@Test
public void timeFormatter_TwoFloats() {
Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a short string that has two floats %f and %f in it", value, value);
@@ -140,7 +140,7 @@
@Test
public void timeStringBuilder_OneFloat() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
sb.append("this is a reasonably short string that has a float ");
@@ -151,7 +151,7 @@
@Test
public void timeFormatter_OneString() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Formatter f = new Formatter();
f.format("this is a reasonably short string that has a string %s in it", "hello");
@@ -160,7 +160,7 @@
@Test
public void timeStringBuilder_OneString() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
sb.append("this is a reasonably short string that has a string ");
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
index 833575a..a09ad80 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class IdnPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeToUnicode() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
IDN.toASCII("fass.de");
IDN.toASCII("faß.de");
@@ -51,7 +51,7 @@
@Test
public void timeToAscii() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
IDN.toUnicode("xn--fss-qla.de");
IDN.toUnicode("xn--n00d.com");
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
index 1c901c8..be22814 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class IntConstantDivisionPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeDivideIntByConstant2() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= 2;
}
@@ -43,7 +43,7 @@
@Test
public void timeDivideIntByConstant8() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= 8;
}
@@ -52,7 +52,7 @@
@Test
public void timeDivideIntByConstant10() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= 10;
}
@@ -61,7 +61,7 @@
@Test
public void timeDivideIntByConstant100() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= 100;
}
@@ -70,7 +70,7 @@
@Test
public void timeDivideIntByConstant100_HandOptimized() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = (int) ((0x51eb851fL * result) >>> 37);
}
@@ -79,7 +79,7 @@
@Test
public void timeDivideIntByConstant2048() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= 2048;
}
@@ -89,7 +89,7 @@
public void timeDivideIntByVariable2() {
int result = 1;
int factor = 2;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= factor;
}
@@ -99,7 +99,7 @@
public void timeDivideIntByVariable10() {
int result = 1;
int factor = 10;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result /= factor;
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
index 3d3af4c..4337c90 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class IntConstantMultiplicationPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeMultiplyIntByConstant6() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 6;
}
@@ -43,7 +43,7 @@
@Test
public void timeMultiplyIntByConstant7() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 7;
}
@@ -52,7 +52,7 @@
@Test
public void timeMultiplyIntByConstant8() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 8;
}
@@ -61,7 +61,7 @@
@Test
public void timeMultiplyIntByConstant8_Shift() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result <<= 3;
}
@@ -70,7 +70,7 @@
@Test
public void timeMultiplyIntByConstant10() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 10;
}
@@ -79,7 +79,7 @@
@Test
public void timeMultiplyIntByConstant10_Shift() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = (result + (result << 2)) << 1;
}
@@ -88,7 +88,7 @@
@Test
public void timeMultiplyIntByConstant2047() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 2047;
}
@@ -97,7 +97,7 @@
@Test
public void timeMultiplyIntByConstant2048() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 2048;
}
@@ -106,7 +106,7 @@
@Test
public void timeMultiplyIntByConstant2049() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= 2049;
}
@@ -116,7 +116,7 @@
public void timeMultiplyIntByVariable10() {
int result = 1;
int factor = 10;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= factor;
}
@@ -126,7 +126,7 @@
public void timeMultiplyIntByVariable8() {
int result = 1;
int factor = 8;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result *= factor;
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
index 7c86633..1b6c502 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class IntConstantRemainderPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeRemainderIntByConstant2() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= 2;
}
@@ -43,7 +43,7 @@
@Test
public void timeRemainderIntByConstant8() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= 8;
}
@@ -52,7 +52,7 @@
@Test
public void timeRemainderIntByConstant10() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= 10;
}
@@ -61,7 +61,7 @@
@Test
public void timeRemainderIntByConstant100() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= 100;
}
@@ -70,7 +70,7 @@
@Test
public void timeRemainderIntByConstant2048() {
int result = 1;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= 2048;
}
@@ -80,7 +80,7 @@
public void timeRemainderIntByVariable2() {
int result = 1;
int factor = 2;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= factor;
}
@@ -90,7 +90,7 @@
public void timeRemainderIntByVariable10() {
int result = 1;
int factor = 10;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result %= factor;
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java
index e2a9dcc..170bb58 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java
@@ -16,20 +16,20 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import org.junit.Rule;
import org.junit.Test;
public class IntegerPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeLongSignumBranch() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += signum1(-(++i));
t += signum1(0);
@@ -41,7 +41,7 @@
public void timeLongSignumBranchFree() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += signum2(-(++i));
t += signum2(0);
@@ -61,7 +61,7 @@
public void timeLongBitCount_BitSet() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += pop((long) ++i);
}
@@ -89,7 +89,7 @@
public void timeLongBitCount_2Int() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += pop2((long) ++i);
}
@@ -105,7 +105,7 @@
public void timeLongBitCount_Long() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += Long.bitCount((long) ++i);
}
@@ -140,7 +140,7 @@
public void timeNumberOfTrailingZerosHD() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += numberOfTrailingZerosHD(++i);
}
@@ -150,7 +150,7 @@
public void timeNumberOfTrailingZerosOL() {
int t = 0;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
t += numberOfTrailingZerosOL(++i);
}
@@ -163,7 +163,7 @@
"0", "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678"
};
int t = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int j = 0; j < intStrings.length; ++j) {
t += Integer.valueOf(intStrings[j]);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
index 669bfbf..0aa854e 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class IntegralToStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final int SMALL = 12;
private static final int MEDIUM = 12345;
@@ -37,7 +37,7 @@
@Test
public void time_IntegerToString_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(SMALL);
}
@@ -45,7 +45,7 @@
@Test
public void time_IntegerToString_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(MEDIUM);
}
@@ -53,7 +53,7 @@
@Test
public void time_IntegerToString_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(LARGE);
}
@@ -61,7 +61,7 @@
@Test
public void time_IntegerToString2_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(SMALL, 2);
}
@@ -69,7 +69,7 @@
@Test
public void time_IntegerToString2_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(MEDIUM, 2);
}
@@ -77,7 +77,7 @@
@Test
public void time_IntegerToString2_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(LARGE, 2);
}
@@ -85,7 +85,7 @@
@Test
public void time_IntegerToString10_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(SMALL, 10);
}
@@ -93,7 +93,7 @@
@Test
public void time_IntegerToString10_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(MEDIUM, 10);
}
@@ -101,7 +101,7 @@
@Test
public void time_IntegerToString10_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(LARGE, 10);
}
@@ -109,7 +109,7 @@
@Test
public void time_IntegerToString16_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(SMALL, 16);
}
@@ -117,7 +117,7 @@
@Test
public void time_IntegerToString16_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(MEDIUM, 16);
}
@@ -125,7 +125,7 @@
@Test
public void time_IntegerToString16_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toString(LARGE, 16);
}
@@ -133,7 +133,7 @@
@Test
public void time_IntegerToBinaryString_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toBinaryString(SMALL);
}
@@ -141,7 +141,7 @@
@Test
public void time_IntegerToBinaryString_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toBinaryString(MEDIUM);
}
@@ -149,7 +149,7 @@
@Test
public void time_IntegerToBinaryString_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toBinaryString(LARGE);
}
@@ -157,7 +157,7 @@
@Test
public void time_IntegerToHexString_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toHexString(SMALL);
}
@@ -165,7 +165,7 @@
@Test
public void time_IntegerToHexString_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toHexString(MEDIUM);
}
@@ -173,7 +173,7 @@
@Test
public void time_IntegerToHexString_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Integer.toHexString(LARGE);
}
@@ -181,7 +181,7 @@
@Test
public void time_StringBuilder_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new StringBuilder().append(SMALL);
}
@@ -189,7 +189,7 @@
@Test
public void time_StringBuilder_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new StringBuilder().append(MEDIUM);
}
@@ -197,7 +197,7 @@
@Test
public void time_StringBuilder_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new StringBuilder().append(LARGE);
}
@@ -205,7 +205,7 @@
@Test
public void time_Formatter_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%d", SMALL);
}
@@ -213,7 +213,7 @@
@Test
public void time_Formatter_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%d", MEDIUM);
}
@@ -221,7 +221,7 @@
@Test
public void time_Formatter_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%d", LARGE);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
index cda8512..9b3d7a0 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -36,7 +36,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class KeyPairGeneratorPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -78,7 +78,7 @@
@Parameters(method = "getData")
public void time(Algorithm algorithm, Implementation implementation) throws Exception {
setUp(algorithm, implementation);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
KeyPair keyPair = mGenerator.generateKeyPair();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
index 8b062d3..1a9e19a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -39,7 +39,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class LoopingBackwardsPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(new Object[][] {{2}, {20}, {2000}, {20000000}});
@@ -49,7 +49,7 @@
@Parameters(method = "getData")
public void timeForwards(int max) {
int fake = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int j = 0; j < max; j++) {
fake += j;
@@ -61,7 +61,7 @@
@Parameters(method = "getData")
public void timeBackwards(int max) {
int fake = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int j = max - 1; j >= 0; j--) {
fake += j;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
index bcf556c..a8a704c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MathPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final double mDouble = 1.2;
private final float mFloat = 1.2f;
@@ -48,7 +48,7 @@
@Test
public void timeAbsD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.abs(mDouble);
}
@@ -57,7 +57,7 @@
@Test
public void timeAbsF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.abs(mFloat);
}
@@ -66,7 +66,7 @@
@Test
public void timeAbsI() {
int result = mInt;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.abs(mInt);
}
@@ -75,7 +75,7 @@
@Test
public void timeAbsL() {
long result = mLong;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.abs(mLong);
}
@@ -84,7 +84,7 @@
@Test
public void timeAcos() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.acos(mDouble);
}
@@ -93,7 +93,7 @@
@Test
public void timeAsin() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.asin(mDouble);
}
@@ -102,7 +102,7 @@
@Test
public void timeAtan() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.atan(mDouble);
}
@@ -111,7 +111,7 @@
@Test
public void timeAtan2() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.atan2(3, 4);
}
@@ -120,7 +120,7 @@
@Test
public void timeCbrt() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.cbrt(mDouble);
}
@@ -129,7 +129,7 @@
@Test
public void timeCeil() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.ceil(mDouble);
}
@@ -138,7 +138,7 @@
@Test
public void timeCopySignD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.copySign(mDouble, mDouble);
}
@@ -147,7 +147,7 @@
@Test
public void timeCopySignF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.copySign(mFloat, mFloat);
}
@@ -156,7 +156,7 @@
@Test
public void timeCopySignD_strict() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = StrictMath.copySign(mDouble, mDouble);
}
@@ -165,7 +165,7 @@
@Test
public void timeCopySignF_strict() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = StrictMath.copySign(mFloat, mFloat);
}
@@ -174,7 +174,7 @@
@Test
public void timeCos() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.cos(mDouble);
}
@@ -183,7 +183,7 @@
@Test
public void timeCosh() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.cosh(mDouble);
}
@@ -192,7 +192,7 @@
@Test
public void timeExp() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.exp(mDouble);
}
@@ -201,7 +201,7 @@
@Test
public void timeExpm1() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.expm1(mDouble);
}
@@ -210,7 +210,7 @@
@Test
public void timeFloor() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.floor(mDouble);
}
@@ -219,7 +219,7 @@
@Test
public void timeGetExponentD() {
int result = mInt;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.getExponent(mDouble);
}
@@ -228,7 +228,7 @@
@Test
public void timeGetExponentF() {
int result = mInt;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.getExponent(mFloat);
}
@@ -237,7 +237,7 @@
@Test
public void timeHypot() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.hypot(mDouble, mDouble);
}
@@ -246,7 +246,7 @@
@Test
public void timeIEEEremainder() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.IEEEremainder(mDouble, mDouble);
}
@@ -255,7 +255,7 @@
@Test
public void timeLog() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.log(mDouble);
}
@@ -264,7 +264,7 @@
@Test
public void timeLog10() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.log10(mDouble);
}
@@ -273,7 +273,7 @@
@Test
public void timeLog1p() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.log1p(mDouble);
}
@@ -282,7 +282,7 @@
@Test
public void timeMaxD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.max(mDouble, mDouble);
}
@@ -291,7 +291,7 @@
@Test
public void timeMaxF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.max(mFloat, mFloat);
}
@@ -300,7 +300,7 @@
@Test
public void timeMaxI() {
int result = mInt;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.max(mInt, mInt);
}
@@ -309,7 +309,7 @@
@Test
public void timeMaxL() {
long result = mLong;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.max(mLong, mLong);
}
@@ -318,7 +318,7 @@
@Test
public void timeMinD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.min(mDouble, mDouble);
}
@@ -327,7 +327,7 @@
@Test
public void timeMinF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.min(mFloat, mFloat);
}
@@ -336,7 +336,7 @@
@Test
public void timeMinI() {
int result = mInt;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.min(mInt, mInt);
}
@@ -345,7 +345,7 @@
@Test
public void timeMinL() {
long result = mLong;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.min(mLong, mLong);
}
@@ -354,7 +354,7 @@
@Test
public void timeNextAfterD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.nextAfter(mDouble, mDouble);
}
@@ -363,7 +363,7 @@
@Test
public void timeNextAfterF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.nextAfter(mFloat, mFloat);
}
@@ -372,7 +372,7 @@
@Test
public void timeNextUpD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.nextUp(mDouble);
}
@@ -381,7 +381,7 @@
@Test
public void timeNextUpF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.nextUp(mFloat);
}
@@ -390,7 +390,7 @@
@Test
public void timePow() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.pow(mDouble, mDouble);
}
@@ -399,7 +399,7 @@
@Test
public void timeRandom() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.random();
}
@@ -408,7 +408,7 @@
@Test
public void timeRint() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.rint(mDouble);
}
@@ -417,7 +417,7 @@
@Test
public void timeRoundD() {
long result = mLong;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.round(mDouble);
}
@@ -426,7 +426,7 @@
@Test
public void timeRoundF() {
int result = mInt;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.round(mFloat);
}
@@ -435,7 +435,7 @@
@Test
public void timeScalbD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.scalb(mDouble, 5);
}
@@ -444,7 +444,7 @@
@Test
public void timeScalbF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.scalb(mFloat, 5);
}
@@ -453,7 +453,7 @@
@Test
public void timeSignumD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.signum(mDouble);
}
@@ -462,7 +462,7 @@
@Test
public void timeSignumF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.signum(mFloat);
}
@@ -471,7 +471,7 @@
@Test
public void timeSin() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.sin(mDouble);
}
@@ -480,7 +480,7 @@
@Test
public void timeSinh() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.sinh(mDouble);
}
@@ -489,7 +489,7 @@
@Test
public void timeSqrt() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.sqrt(mDouble);
}
@@ -498,7 +498,7 @@
@Test
public void timeTan() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.tan(mDouble);
}
@@ -507,7 +507,7 @@
@Test
public void timeTanh() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.tanh(mDouble);
}
@@ -516,7 +516,7 @@
@Test
public void timeToDegrees() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.toDegrees(mDouble);
}
@@ -525,7 +525,7 @@
@Test
public void timeToRadians() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.toRadians(mDouble);
}
@@ -534,7 +534,7 @@
@Test
public void timeUlpD() {
double result = mDouble;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.ulp(mDouble);
}
@@ -543,7 +543,7 @@
@Test
public void timeUlpF() {
float result = mFloat;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result = Math.ulp(mFloat);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
index 8325dae..6da9666 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -36,7 +36,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class MessageDigestPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -97,7 +97,7 @@
@Test
@Parameters(method = "getData")
public void time(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
digest.update(DATA, 0, DATA_SIZE);
@@ -108,7 +108,7 @@
@Test
@Parameters(method = "getData")
public void timeLargeArray(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
digest.update(LARGE_DATA, 0, LARGE_DATA_SIZE);
@@ -119,7 +119,7 @@
@Test
@Parameters(method = "getData")
public void timeSmallChunkOfLargeArray(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
digest.update(LARGE_DATA, LARGE_DATA_SIZE / 2, DATA_SIZE);
@@ -130,7 +130,7 @@
@Test
@Parameters(method = "getData")
public void timeSmallByteBuffer(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
SMALL_BUFFER.position(0);
@@ -143,7 +143,7 @@
@Test
@Parameters(method = "getData")
public void timeSmallDirectByteBuffer(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
SMALL_DIRECT_BUFFER.position(0);
@@ -156,7 +156,7 @@
@Test
@Parameters(method = "getData")
public void timeLargeByteBuffer(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
LARGE_BUFFER.position(0);
@@ -169,7 +169,7 @@
@Test
@Parameters(method = "getData")
public void timeLargeDirectByteBuffer(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
LARGE_DIRECT_BUFFER.position(0);
@@ -182,7 +182,7 @@
@Test
@Parameters(method = "getData")
public void timeSmallChunkOfLargeByteBuffer(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
LARGE_BUFFER.position(LARGE_BUFFER.capacity() / 2);
@@ -195,7 +195,7 @@
@Test
@Parameters(method = "getData")
public void timeSmallChunkOfLargeDirectByteBuffer(Algorithm algorithm) throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
LARGE_DIRECT_BUFFER.position(LARGE_DIRECT_BUFFER.capacity() / 2);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
index 266d42c..060d18f 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -35,7 +35,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class MutableIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
enum Kind {
ARRAY() {
@@ -105,21 +105,21 @@
@Test
@Parameters(method = "getData")
public void timeCreate(Kind kind) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
kind.timeCreate(state);
}
@Test
@Parameters(method = "getData")
public void timeIncrement(Kind kind) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
kind.timeIncrement(state);
}
@Test
@Parameters(method = "getData")
public void timeGet(Kind kind) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
kind.timeGet(state);
}
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
index c2f84fb..7cb3b22 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,13 +32,13 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class NumberFormatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static Locale sLocale = Locale.getDefault(Locale.Category.FORMAT);
@Test
public void time_instantiation() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
NumberFormat.getInstance(sLocale);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
index cdf0911..272b45a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -36,12 +36,12 @@
@LargeTest
public class NumberFormatTrivialFormatLongPerfTest {
@Rule
- public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeNumberFormatTrivialFormatLong() {
NumberFormat nf = NumberFormat.getInstance(Locale.US);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
nf.format(1024L);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
index 51f47bb..c3a0966 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -39,7 +39,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class PriorityQueuePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -108,7 +108,7 @@
// At most allow the queue to empty 10%.
int resizingThreshold = queueSize / 10;
int i = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
// Reset queue every so often. This will be called more often for smaller
// queueSizes, but since a copy is linear, it will also cost proportionally
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
index 1f20cae..2ac56be 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public final class PropertyAccessPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private View mView = new View();
private Method mSetX;
@@ -50,7 +50,7 @@
@Test
public void timeDirectSetter() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mView.mSetX(0.1f);
}
@@ -58,7 +58,7 @@
@Test
public void timeDirectFieldSet() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mView.mX = 0.1f;
}
@@ -66,7 +66,7 @@
@Test
public void timeDirectSetterAndBomXing() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float value = 0.1f;
mView.mSetX(value);
@@ -75,7 +75,7 @@
@Test
public void timeDirectFieldSetAndBomXing() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float value = 0.1f;
mView.mX = value;
@@ -84,7 +84,7 @@
@Test
public void timeReflectionSetterAndTwoBomXes() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mSetX.invoke(mView, 0.1f);
}
@@ -92,7 +92,7 @@
@Test
public void timeReflectionSetterAndOneBomX() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mArgsBomX[0] = 0.1f;
mSetX.invoke(mView, mArgsBomX);
@@ -101,7 +101,7 @@
@Test
public void timeReflectionFieldSet() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mX.setFloat(mView, 0.1f);
}
@@ -109,7 +109,7 @@
@Test
public void timeGeneratedSetter() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mGeneratedSetter.setFloat(mView, 0.1f);
}
@@ -117,7 +117,7 @@
@Test
public void timeGeneratedFieldSet() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mGeneratedField.setFloat(mView, 0.1f);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
index 0c16265..7ad0141 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,11 +34,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ProviderPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeStableProviders() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Cipher c = Cipher.getInstance("RSA");
}
@@ -46,7 +46,7 @@
@Test
public void timeWithNewProvider() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Security.addProvider(new MockProvider());
try {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
index 5f1bfc2..c7b6cb5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,11 +32,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class RandomPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeNewRandom() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Random rng = new Random();
rng.nextInt();
@@ -46,7 +46,7 @@
@Test
public void timeReusedRandom() throws Exception {
Random rng = new Random();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
rng.nextInt();
}
@@ -55,7 +55,7 @@
@Test
public void timeReusedSecureRandom() throws Exception {
SecureRandom rng = new SecureRandom();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
rng.nextInt();
}
@@ -63,7 +63,7 @@
@Test
public void timeNewSecureRandom() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
SecureRandom rng = new SecureRandom();
rng.nextInt();
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
index 008c94c..44e5f22 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class RealToStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final float SMALL = -123.45f;
private static final float MEDIUM = -123.45e8f;
@@ -37,7 +37,7 @@
@Test
public void timeFloat_toString_NaN() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(Float.NaN);
}
@@ -45,7 +45,7 @@
@Test
public void timeFloat_toString_NEGATIVE_INFINITY() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(Float.NEGATIVE_INFINITY);
}
@@ -53,7 +53,7 @@
@Test
public void timeFloat_toString_POSITIVE_INFINITY() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(Float.POSITIVE_INFINITY);
}
@@ -61,7 +61,7 @@
@Test
public void timeFloat_toString_zero() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(0.0f);
}
@@ -69,7 +69,7 @@
@Test
public void timeFloat_toString_minusZero() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(-0.0f);
}
@@ -77,7 +77,7 @@
@Test
public void timeFloat_toString_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(SMALL);
}
@@ -85,7 +85,7 @@
@Test
public void timeFloat_toString_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(MEDIUM);
}
@@ -93,7 +93,7 @@
@Test
public void timeFloat_toString_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.toString(LARGE);
}
@@ -101,7 +101,7 @@
@Test
public void timeStringBuilder_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new StringBuilder().append(SMALL);
}
@@ -109,7 +109,7 @@
@Test
public void timeStringBuilder_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new StringBuilder().append(MEDIUM);
}
@@ -117,7 +117,7 @@
@Test
public void timeStringBuilder_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new StringBuilder().append(LARGE);
}
@@ -125,7 +125,7 @@
@Test
public void timeFormatter_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%f", SMALL);
}
@@ -133,7 +133,7 @@
@Test
public void timeFormatter_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%f", MEDIUM);
}
@@ -141,7 +141,7 @@
@Test
public void timeFormatter_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%f", LARGE);
}
@@ -149,7 +149,7 @@
@Test
public void timeFormatter_dot2f_small() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%.2f", SMALL);
}
@@ -157,7 +157,7 @@
@Test
public void timeFormatter_dot2f_medium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%.2f", MEDIUM);
}
@@ -165,7 +165,7 @@
@Test
public void timeFormatter_dot2f_large() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
String.format("%.2f", LARGE);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
index 45b623d..6e00b1083 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,12 +33,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectionPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeObject_getClass() throws Exception {
C c = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
c.getClass();
}
@@ -47,7 +47,7 @@
@Test
public void timeClass_getField() throws Exception {
Class<?> klass = C.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.getField("f");
}
@@ -56,7 +56,7 @@
@Test
public void timeClass_getDeclaredField() throws Exception {
Class<?> klass = C.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.getDeclaredField("f");
}
@@ -65,7 +65,7 @@
@Test
public void timeClass_getConstructor() throws Exception {
Class<?> klass = C.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.getConstructor();
}
@@ -75,7 +75,7 @@
public void timeClass_newInstance() throws Exception {
Class<?> klass = C.class;
Constructor constructor = klass.getConstructor();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
constructor.newInstance();
}
@@ -84,7 +84,7 @@
@Test
public void timeClass_getMethod() throws Exception {
Class<?> klass = C.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.getMethod("m");
}
@@ -93,7 +93,7 @@
@Test
public void timeClass_getDeclaredMethod() throws Exception {
Class<?> klass = C.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.getDeclaredMethod("m");
}
@@ -104,7 +104,7 @@
Class<?> klass = C.class;
Field f = klass.getDeclaredField("f");
C instance = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
f.setInt(instance, 1);
}
@@ -115,7 +115,7 @@
Class<?> klass = C.class;
Field f = klass.getDeclaredField("f");
C instance = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
f.getInt(instance);
}
@@ -126,7 +126,7 @@
Class<?> klass = C.class;
Method m = klass.getDeclaredMethod("m");
C instance = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
m.invoke(instance);
}
@@ -136,7 +136,7 @@
public void timeMethod_invokeStaticV() throws Exception {
Class<?> klass = C.class;
Method m = klass.getDeclaredMethod("sm");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
m.invoke(null);
}
@@ -147,7 +147,7 @@
Class<?> klass = C.class;
Method m = klass.getDeclaredMethod("setField", int.class);
C instance = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
m.invoke(instance, 1);
}
@@ -159,7 +159,7 @@
Method m = klass.getDeclaredMethod("setField", int.class);
C instance = new C();
Integer one = Integer.valueOf(1);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
m.invoke(instance, one);
}
@@ -169,7 +169,7 @@
public void timeMethod_invokeStaticI() throws Exception {
Class<?> klass = C.class;
Method m = klass.getDeclaredMethod("setStaticField", int.class);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
m.invoke(null, 1);
}
@@ -180,7 +180,7 @@
Class<?> klass = C.class;
Method m = klass.getDeclaredMethod("setStaticField", int.class);
Integer one = Integer.valueOf(1);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
m.invoke(null, one);
}
@@ -189,7 +189,7 @@
@Test
public void timeRegularMethodInvocation() throws Exception {
C instance = new C();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
instance.setField(1);
}
@@ -197,7 +197,7 @@
@Test
public void timeRegularConstructor() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
new C();
}
@@ -206,7 +206,7 @@
@Test
public void timeClass_classNewInstance() throws Exception {
Class<?> klass = C.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.newInstance();
}
@@ -216,7 +216,7 @@
public void timeClass_isInstance() throws Exception {
D d = new D();
Class<?> klass = IC.class;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
klass.isInstance(d);
}
@@ -224,7 +224,7 @@
@Test
public void timeGetInstanceField() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
// TODO: Write a test script that generates both the classes we're
// reflecting on and the test case for each of its fields.
@@ -234,7 +234,7 @@
@Test
public void timeGetStaticField() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
R.class.getField("WEEK_NUMBER_COLOR");
}
@@ -242,7 +242,7 @@
@Test
public void timeGetInterfaceStaticField() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
F.class.getField("SF");
}
@@ -250,7 +250,7 @@
@Test
public void timeGetSuperClassField() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
G.class.getField("f");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
index da69f9f..5a9b5c3 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,11 +35,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SSLLoopbackPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void time() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TestSSLContext context =
TestSSLContext.create(TestKeyStore.getClient(), TestKeyStore.getServer());
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
index 9f2c312..6d48cf2 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SSLSocketFactoryPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void time() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
SSLSocketFactory.getDefault();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
index 7c60c05..8641629 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -37,7 +37,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class SchemePrefixPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
enum Strategy {
JAVA() {
@@ -94,7 +94,7 @@
@Test
@Parameters(method = "getData")
public void timeSchemePrefix(Strategy strategy) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
strategy.execute("http://android.com");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
index 1812983..afd1191 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -37,7 +37,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SerializationPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static byte[] bytes(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
@@ -110,7 +110,7 @@
public void timeWriteNoObjects() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
ObjectOutputStream out = new ObjectOutputStream(baos);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
out.reset();
baos.reset();
@@ -121,7 +121,7 @@
private void readSingleObject(Object object) throws Exception {
byte[] bytes = bytes(object);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ObjectInputStream in = new ObjectInputStream(bais);
in.readObject();
@@ -133,7 +133,7 @@
private void writeSingleObject(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
ObjectOutputStream out = new ObjectOutputStream(baos);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
out.writeObject(o);
out.reset();
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
index 34e9bfb..6c26133 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
@@ -15,8 +15,8 @@
*/
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -41,7 +41,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class SignaturePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -117,7 +117,7 @@
@Parameters(method = "getData")
public void timeSign(Algorithm algorithm, Implementation implementation) throws Exception {
setUp(algorithm);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Signature signer;
switch (implementation) {
@@ -140,7 +140,7 @@
@Parameters(method = "getData")
public void timeVerify(Algorithm algorithm, Implementation implementation) throws Exception {
setUp(algorithm);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Signature verifier;
switch (implementation) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
index 2fe6798..274b51f 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -37,11 +37,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SimpleDateFormatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void time_createFormatWithTimeZone() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
}
@@ -50,7 +50,7 @@
@Test
public void time_parseWithTimeZoneShort() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
sdf.parse("2000.01.01 PST");
}
@@ -59,7 +59,7 @@
@Test
public void time_parseWithTimeZoneLong() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
sdf.parse("2000.01.01 Pacific Standard Time");
}
@@ -68,7 +68,7 @@
@Test
public void time_parseWithoutTimeZone() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
sdf.parse("2000.01.01");
}
@@ -76,7 +76,7 @@
@Test
public void time_createAndParseWithTimeZoneShort() throws ParseException {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
sdf.parse("2000.01.01 PST");
@@ -85,7 +85,7 @@
@Test
public void time_createAndParseWithTimeZoneLong() throws ParseException {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
sdf.parse("2000.01.01 Pacific Standard Time");
@@ -95,7 +95,7 @@
@Test
public void time_formatWithTimeZoneShort() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
sdf.format(new Date());
}
@@ -104,7 +104,7 @@
@Test
public void time_formatWithTimeZoneLong() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
sdf.format(new Date());
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
index fbe3cef..b4c427b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StrictMathPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final double mDouble = 1.2;
private final float mFloat = 1.2f;
@@ -74,7 +74,7 @@
@Test
public void timeAbsD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.abs(mDouble);
}
@@ -82,7 +82,7 @@
@Test
public void timeAbsF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.abs(mFloat);
}
@@ -90,7 +90,7 @@
@Test
public void timeAbsI() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.abs(mInt);
}
@@ -98,7 +98,7 @@
@Test
public void timeAbsL() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.abs(mLong);
}
@@ -106,7 +106,7 @@
@Test
public void timeAcos() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.acos(mDouble);
}
@@ -114,7 +114,7 @@
@Test
public void timeAsin() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.asin(mDouble);
}
@@ -122,7 +122,7 @@
@Test
public void timeAtan() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.atan(mDouble);
}
@@ -130,7 +130,7 @@
@Test
public void timeAtan2() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.atan2(3, 4);
}
@@ -138,7 +138,7 @@
@Test
public void timeCbrt() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.cbrt(mDouble);
}
@@ -146,7 +146,7 @@
@Test
public void timeCeilOverInterestingValues() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < CEIL_DOUBLES.length; ++i) {
StrictMath.ceil(CEIL_DOUBLES[i]);
@@ -156,7 +156,7 @@
@Test
public void timeCopySignD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.copySign(mDouble, mDouble);
}
@@ -164,7 +164,7 @@
@Test
public void timeCopySignF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.copySign(mFloat, mFloat);
}
@@ -172,7 +172,7 @@
@Test
public void timeCos() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.cos(mDouble);
}
@@ -180,7 +180,7 @@
@Test
public void timeCosh() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.cosh(mDouble);
}
@@ -188,7 +188,7 @@
@Test
public void timeExp() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.exp(mDouble);
}
@@ -196,7 +196,7 @@
@Test
public void timeExpm1() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.expm1(mDouble);
}
@@ -204,7 +204,7 @@
@Test
public void timeFloorOverInterestingValues() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < FLOOR_DOUBLES.length; ++i) {
StrictMath.floor(FLOOR_DOUBLES[i]);
@@ -214,7 +214,7 @@
@Test
public void timeGetExponentD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.getExponent(mDouble);
}
@@ -222,7 +222,7 @@
@Test
public void timeGetExponentF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.getExponent(mFloat);
}
@@ -230,7 +230,7 @@
@Test
public void timeHypot() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.hypot(mDouble, mDouble);
}
@@ -238,7 +238,7 @@
@Test
public void timeIEEEremainder() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.IEEEremainder(mDouble, mDouble);
}
@@ -246,7 +246,7 @@
@Test
public void timeLog() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.log(mDouble);
}
@@ -254,7 +254,7 @@
@Test
public void timeLog10() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.log10(mDouble);
}
@@ -262,7 +262,7 @@
@Test
public void timeLog1p() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.log1p(mDouble);
}
@@ -270,7 +270,7 @@
@Test
public void timeMaxD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.max(mDouble, mDouble);
}
@@ -278,7 +278,7 @@
@Test
public void timeMaxF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.max(mFloat, mFloat);
}
@@ -286,7 +286,7 @@
@Test
public void timeMaxI() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.max(mInt, mInt);
}
@@ -294,7 +294,7 @@
@Test
public void timeMaxL() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.max(mLong, mLong);
}
@@ -302,7 +302,7 @@
@Test
public void timeMinD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.min(mDouble, mDouble);
}
@@ -310,7 +310,7 @@
@Test
public void timeMinF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.min(mFloat, mFloat);
}
@@ -318,7 +318,7 @@
@Test
public void timeMinI() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.min(mInt, mInt);
}
@@ -326,7 +326,7 @@
@Test
public void timeMinL() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.min(mLong, mLong);
}
@@ -334,7 +334,7 @@
@Test
public void timeNextAfterD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.nextAfter(mDouble, mDouble);
}
@@ -342,7 +342,7 @@
@Test
public void timeNextAfterF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.nextAfter(mFloat, mFloat);
}
@@ -350,7 +350,7 @@
@Test
public void timeNextUpD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.nextUp(mDouble);
}
@@ -358,7 +358,7 @@
@Test
public void timeNextUpF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.nextUp(mFloat);
}
@@ -366,7 +366,7 @@
@Test
public void timePow() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.pow(mDouble, mDouble);
}
@@ -374,7 +374,7 @@
@Test
public void timeRandom() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.random();
}
@@ -382,7 +382,7 @@
@Test
public void timeRint() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.rint(mDouble);
}
@@ -390,7 +390,7 @@
@Test
public void timeRoundD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.round(mDouble);
}
@@ -398,7 +398,7 @@
@Test
public void timeRoundF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.round(mFloat);
}
@@ -406,7 +406,7 @@
@Test
public void timeScalbD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.scalb(mDouble, 5);
}
@@ -414,7 +414,7 @@
@Test
public void timeScalbF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.scalb(mFloat, 5);
}
@@ -422,7 +422,7 @@
@Test
public void timeSignumD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.signum(mDouble);
}
@@ -430,7 +430,7 @@
@Test
public void timeSignumF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.signum(mFloat);
}
@@ -438,7 +438,7 @@
@Test
public void timeSin() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.sin(mDouble);
}
@@ -446,7 +446,7 @@
@Test
public void timeSinh() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.sinh(mDouble);
}
@@ -454,7 +454,7 @@
@Test
public void timeSqrt() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.sqrt(mDouble);
}
@@ -462,7 +462,7 @@
@Test
public void timeTan() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.tan(mDouble);
}
@@ -470,7 +470,7 @@
@Test
public void timeTanh() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.tanh(mDouble);
}
@@ -478,7 +478,7 @@
@Test
public void timeToDegrees() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.toDegrees(mDouble);
}
@@ -486,7 +486,7 @@
@Test
public void timeToRadians() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.toRadians(mDouble);
}
@@ -494,7 +494,7 @@
@Test
public void timeUlpD() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.ulp(mDouble);
}
@@ -502,7 +502,7 @@
@Test
public void timeUlpF() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StrictMath.ulp(mFloat);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
index 0155154..2235cc5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,13 +30,13 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringBuilderPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public int mLength = 100;
@Test
public void timeAppendBoolean() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -47,7 +47,7 @@
@Test
public void timeAppendChar() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -59,7 +59,7 @@
@Test
public void timeAppendCharArray() {
char[] chars = "chars".toCharArray();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -71,7 +71,7 @@
@Test
public void timeAppendCharSequence() {
CharSequence cs = "chars";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -83,7 +83,7 @@
@Test
public void timeAppendSubCharSequence() {
CharSequence cs = "chars";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -95,7 +95,7 @@
@Test
public void timeAppendDouble() {
double d = 1.2;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -107,7 +107,7 @@
@Test
public void timeAppendFloat() {
float f = 1.2f;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -119,7 +119,7 @@
@Test
public void timeAppendInt() {
int n = 123;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -131,7 +131,7 @@
@Test
public void timeAppendLong() {
long l = 123;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -150,7 +150,7 @@
return "constant";
}
};
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
@@ -162,7 +162,7 @@
@Test
public void timeAppendString() {
String s = "chars";
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < mLength; ++j) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
index 5533745..9ab5000 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,7 +38,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringEqualsPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final String mLong1 =
"Ahead-of-time compilation is possible as the compiler may just convert an instruction"
@@ -226,7 +226,7 @@
// Benchmark cases of String.equals(null)
@Test
public void timeEqualsNull() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mMediumStrings.length; i++) {
mMediumStrings[i][0].equals(null);
@@ -237,7 +237,7 @@
// Benchmark cases with very short (<5 character) Strings
@Test
public void timeEqualsShort() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mShortStrings.length; i++) {
mShortStrings[i][0].equals(mShortStrings[i][1]);
@@ -248,7 +248,7 @@
// Benchmark cases with medium length (10-15 character) Strings
@Test
public void timeEqualsMedium() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mMediumStrings.length; i++) {
mMediumStrings[i][0].equals(mMediumStrings[i][1]);
@@ -259,7 +259,7 @@
// Benchmark cases with long (>100 character) Strings
@Test
public void timeEqualsLong() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mLongStrings.length; i++) {
mLongStrings[i][0].equals(mLongStrings[i][1]);
@@ -270,7 +270,7 @@
// Benchmark cases with very long (>1000 character) Strings
@Test
public void timeEqualsVeryLong() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mVeryLongStrings.length; i++) {
mVeryLongStrings[i][0].equals(mVeryLongStrings[i][1]);
@@ -281,7 +281,7 @@
// Benchmark cases with non-word aligned Strings
@Test
public void timeEqualsNonWordAligned() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mNonalignedStrings.length; i++) {
mNonalignedStrings[i][0].equals(mNonalignedStrings[i][1]);
@@ -292,7 +292,7 @@
// Benchmark cases with slight differences in the endings
@Test
public void timeEqualsEnd() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mEndStrings.length; i++) {
mEndStrings[i][0].equals(mEndStrings[i][1]);
@@ -303,7 +303,7 @@
// Benchmark cases of comparing a string to a non-string object
@Test
public void timeEqualsNonString() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
for (int i = 0; i < mMediumStrings.length; i++) {
mMediumStrings[i][0].equals(mObjects[i]);
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
index a5662b0..b1e749c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringIsEmptyPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeIsEmpty_NonEmpty() {
boolean result = true;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result &= !("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".isEmpty());
}
@@ -44,7 +44,7 @@
@Test
public void timeIsEmpty_Empty() {
boolean result = true;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result &= ("".isEmpty());
}
@@ -54,7 +54,7 @@
@Test
public void timeLengthEqualsZero() {
boolean result = true;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result &= !("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".length() == 0);
}
@@ -64,7 +64,7 @@
@Test
public void timeEqualsEmpty() {
boolean result = true;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
result &= !"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".equals("");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
index 41e64f2..9e57591 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringLengthPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeLength() {
int length = 0;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
length = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".length();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
index 2cd2a09..a80514c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -34,7 +34,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class StringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
enum StringLengths {
EMPTY(""),
@@ -69,7 +69,7 @@
@Test
@Parameters(method = "getData")
public void timeHashCode(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.hashCode();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
index 219dccf..78ae395 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -34,7 +34,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class StringReplaceAllPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
// NOTE: These estimates of MOVEABLE / NON_MOVEABLE are based on a knowledge of
// ART implementation details. They make a difference here because JNI calls related
@@ -86,7 +86,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceAllTrivialPatternNonExistent(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replaceAll("fish", "0");
}
@@ -95,7 +95,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceTrivialPatternAllRepeated(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replaceAll("jklm", "0");
}
@@ -104,7 +104,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceAllTrivialPatternSingleOccurrence(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replaceAll("qrst", "0");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
index d6fef5e..73911c7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -34,7 +34,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class StringReplacePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
enum StringLengths {
EMPTY(""),
@@ -80,7 +80,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceCharNonExistent(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replace('z', '0');
}
@@ -89,7 +89,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceCharRepeated(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replace('a', '0');
}
@@ -98,7 +98,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceSingleChar(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replace('q', '0');
}
@@ -107,7 +107,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceSequenceNonExistent(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replace("fish", "0");
}
@@ -116,7 +116,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceSequenceRepeated(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replace("jklm", "0");
}
@@ -125,7 +125,7 @@
@Test
@Parameters(method = "getData")
public void timeReplaceSingleSequence(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.replace("qrst", "0");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
index 9d0ec2f..1539271 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StringSplitPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeStringSplitComma() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
"this,is,a,simple,example".split(",");
}
@@ -43,7 +43,7 @@
@Test
public void timeStringSplitLiteralDot() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
"this.is.a.simple.example".split("\\.");
}
@@ -51,7 +51,7 @@
@Test
public void timeStringSplitNewline() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
"this\nis\na\nsimple\nexample\n".split("\n");
}
@@ -60,7 +60,7 @@
@Test
public void timePatternSplitComma() {
Pattern p = Pattern.compile(",");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
p.split("this,is,a,simple,example");
}
@@ -69,7 +69,7 @@
@Test
public void timePatternSplitLiteralDot() {
Pattern p = Pattern.compile("\\.");
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
p.split("this.is.a.simple.example");
}
@@ -77,7 +77,7 @@
@Test
public void timeStringSplitHard() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
"this,is,a,harder,example".split("[,]");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
index 11950b7..0d5e62b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -35,7 +35,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class StringToBytesPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
enum StringLengths {
EMPTY(""),
@@ -89,7 +89,7 @@
@Test
@Parameters(method = "getData")
public void timeGetBytesUtf8(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.getBytes(StandardCharsets.UTF_8);
}
@@ -98,7 +98,7 @@
@Test
@Parameters(method = "getData")
public void timeGetBytesIso88591(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.getBytes(StandardCharsets.ISO_8859_1);
}
@@ -107,7 +107,7 @@
@Test
@Parameters(method = "getData")
public void timeGetBytesAscii(StringLengths stringLengths) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
stringLengths.mValue.getBytes(StandardCharsets.US_ASCII);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
index 4b27a16..ecdf809 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -34,7 +34,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public class StringToRealPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -53,7 +53,7 @@
@Test
@Parameters(method = "getData")
public void timeFloat_parseFloat(String string) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Float.parseFloat(string);
}
@@ -62,7 +62,7 @@
@Test
@Parameters(method = "getData")
public void timeDouble_parseDouble(String string) {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Double.parseDouble(string);
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
index 0ab012d..2b2a6b5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ThreadLocalPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private static final ThreadLocal<char[]> BUFFER =
new ThreadLocal<char[]>() {
@@ -41,7 +41,7 @@
@Test
public void timeThreadLocal_get() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
BUFFER.get();
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
index ddf410e..6eb8fcc 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class TimeZonePerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeTimeZone_getDefault() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TimeZone.getDefault();
}
@@ -43,7 +43,7 @@
@Test
public void timeTimeZone_getTimeZoneUTC() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TimeZone.getTimeZone("UTC");
}
@@ -52,7 +52,7 @@
@Test
public void timeTimeZone_getTimeZone_default() throws Exception {
String defaultId = TimeZone.getDefault().getID();
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TimeZone.getTimeZone(defaultId);
}
@@ -61,7 +61,7 @@
// A time zone with relatively few transitions.
@Test
public void timeTimeZone_getTimeZone_America_Caracas() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TimeZone.getTimeZone("America/Caracas");
}
@@ -70,7 +70,7 @@
// A time zone with a lot of transitions.
@Test
public void timeTimeZone_getTimeZone_America_Santiago() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TimeZone.getTimeZone("America/Santiago");
}
@@ -78,7 +78,7 @@
@Test
public void timeTimeZone_getTimeZone_GMT_plus_10() throws Exception {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
TimeZone.getTimeZone("GMT+10");
}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
index a38763b..288c646 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
@@ -16,8 +16,8 @@
package android.libcore.regression;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
@@ -42,7 +42,7 @@
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class XMLEntitiesPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
public static Collection<Object[]> getData() {
return Arrays.asList(
@@ -85,7 +85,7 @@
@Parameters(method = "getData")
public void timeXmlParser(int length, float entityFraction) throws Exception {
setUp(length, entityFraction);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
XmlPullParser parser = mXmlPullParserFactory.newPullParser();
parser.setInput(new StringReader(mXml));
@@ -99,7 +99,7 @@
@Parameters(method = "getData")
public void timeDocumentBuilder(int length, float entityFraction) throws Exception {
setUp(length, entityFraction);
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
DocumentBuilder documentBuilder = mDocumentBuilderFactory.newDocumentBuilder();
documentBuilder.parse(new InputSource(new StringReader(mXml)));
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
index 4076c9d..003c957 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectGetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
int mValue;
@@ -47,7 +42,7 @@
@Test
public void run() throws Throwable {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mField.getInt(this);
x = (int) mField.getInt(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
index 2c65dd4..4f21618 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectGetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
String mValue;
@@ -47,7 +42,7 @@
@Test
public void run() throws Throwable {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mField.get(this);
x = (String) mField.get(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
index dcd25db..210014a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectGetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
static int sValue;
@@ -47,7 +42,7 @@
@Test
public void run() throws Throwable {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mField.getInt(null);
x = (int) mField.getInt(null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
index c938a4c..22c6827 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectGetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
static String sValue;
@@ -47,7 +42,7 @@
@Test
public void run() throws Throwable {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mField.get(null);
x = (String) mField.get(null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
index 618e1b5..5b39109 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectSetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
int mValue;
@@ -46,7 +41,7 @@
@Test
public void run() throws Throwable {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.setInt(this, 42);
mField.setInt(this, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
index 8c2e3ca..883e8a7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectSetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
String mValue;
@@ -46,7 +41,7 @@
@Test
public void run() throws Throwable {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.set(this, "qwerty");
mField.set(this, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
index e888cc68..50bc85c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectSetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
static int sValue;
@@ -46,7 +41,7 @@
@Test
public void run() throws Throwable {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.setInt(null, 42);
mField.setInt(null, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
index 7016611..13fa2bf 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
import java.lang.reflect.Field;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ReflectSetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
static String sValue;
@@ -46,7 +41,7 @@
@Test
public void run() throws Throwable {
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mField.set(null, "qwerty");
mField.set(null, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
index 65c82cc..85c9bae9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.compareAndExchangeAcquire(this, mField, ~42);
x = (int) mVh.compareAndExchangeAcquire(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
index a350b61..2b8f430 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.compareAndExchangeAcquire(this, mField, null);
x = (String) mVh.compareAndExchangeAcquire(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
index 34f596e..246fa43 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.compareAndExchangeAcquire(sField, ~42);
x = (int) mVh.compareAndExchangeAcquire(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
index 2216d7b..d12ffae 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
- public VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ public VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
}
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.compareAndExchangeAcquire(sField, null);
x = (String) mVh.compareAndExchangeAcquire(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
index bda551f..5ced115 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.compareAndExchange(this, mField, ~42);
x = (int) mVh.compareAndExchange(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
index f4d7893..b955d50 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.compareAndExchange(this, mField, null);
x = (String) mVh.compareAndExchange(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
index f438087..601ff34 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.compareAndExchangeRelease(this, mField, ~42);
x = (int) mVh.compareAndExchangeRelease(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
index 78df5c0..0e567f9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.compareAndExchangeRelease(this, mField, null);
x = (String) mVh.compareAndExchangeRelease(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
index f45cc62..6be2870 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.compareAndExchangeRelease(sField, ~42);
x = (int) mVh.compareAndExchangeRelease(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
index 08aa7e2..84c186b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
- public VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ public VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
}
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.compareAndExchangeRelease(sField, null);
x = (String) mVh.compareAndExchangeRelease(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
index 5d4b2e0..b093234 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.compareAndExchange(sField, ~42);
x = (int) mVh.compareAndExchange(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
index ba4f2c8..0d2037b4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.compareAndExchange(sField, null);
x = (String) mVh.compareAndExchange(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
index 7fca450..ee31973 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandsetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.compareAndSet(this, mField, ~42);
success = mVh.compareAndSet(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
index 7eb7ac0..0571fef 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandsetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.compareAndSet(this, mField, null);
success = mVh.compareAndSet(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
index ddfd407..f619dab 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.compareAndSet(sField, ~42);
success = mVh.compareAndSet(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
index f1f3968..fc443fa 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.compareAndSet(sField, null);
success = mVh.compareAndSet(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
index 09127c4..bf3d58b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAcquire(this);
x = (int) mVh.getAcquire(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
index 87be4a6..1f4bc31 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetAcquireFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAcquire(this);
x = (String) mVh.getAcquire(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
index 5d5fc11..2085552 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAcquire();
x = (int) mVh.getAcquire();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
index c7034b8..d9c7d7b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAcquire();
x = (String) mVh.getAcquire();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
index f22865b..acd2533 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,9 +33,9 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetArrayLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int ELEMENT_VALUE = 42;
- int[] mArray = { ELEMENT_VALUE };
+ int[] mArray = {ELEMENT_VALUE};
VarHandle mVh;
public VarHandleGetArrayLittleEndianIntPerfTest() throws Throwable {
@@ -55,7 +54,7 @@
public void run() {
int[] a = mArray;
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.get(a, 0);
x = (int) mVh.get(a, 0);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
index fdb9e84..de9944a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,9 +33,9 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetArrayLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String ELEMENT_VALUE = "qwerty";
- String[] mArray = { ELEMENT_VALUE };
+ String[] mArray = {ELEMENT_VALUE};
VarHandle mVh;
public VarHandleGetArrayLittleEndianStringPerfTest() throws Throwable {
@@ -55,7 +54,7 @@
public void run() {
String[] a = mArray;
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.get(a, 0);
x = (String) mVh.get(a, 0);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
index 347b0cf..a863929 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -30,22 +29,22 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
import java.nio.ByteOrder;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetByteArrayViewBigEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int VALUE = 42;
- byte[] mArray1 = { (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE };
- byte[] mArray2 = { (byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE };
+ byte[] mArray1 = {
+ (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE
+ };
+ byte[] mArray2 = {(byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE};
VarHandle mVh;
public VarHandleGetByteArrayViewBigEndianIntPerfTest() throws Throwable {
mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
- }
+ }
@Before
public void setup() {
@@ -59,7 +58,7 @@
public void run() {
byte[] a = mArray1;
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.get(a, 0);
x = (int) mVh.get(a, 0);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
index dedc94f..4999b9b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -30,22 +29,22 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
import java.nio.ByteOrder;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetByteArrayViewLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int VALUE = 42;
- byte[] mArray1 = { (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24) };
- byte[] mArray2 = { (byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24) };
+ byte[] mArray1 = {
+ (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24)
+ };
+ byte[] mArray2 = {(byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24)};
VarHandle mVh;
public VarHandleGetByteArrayViewLittleEndianIntPerfTest() throws Throwable {
mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
- }
+ }
@Before
public void setup() {
@@ -59,7 +58,7 @@
public void run() {
byte[] a = mArray1;
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.get(a, 0);
x = (int) mVh.get(a, 0);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
index 3f0f624..ee80a6f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.get(this);
x = (int) mVh.get(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
index 9db6328..ec29f7a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.get(this);
x = (String) mVh.get(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
index 17b74a8..ee6a669 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetOpaqueFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getOpaque(this);
x = (int) mVh.getOpaque(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
index 5df1380..1702b84 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetOpaqueFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getOpaque(this);
x = (String) mVh.getOpaque(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
index f656ef2..514ddb9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getOpaque();
x = (int) mVh.getOpaque();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
index 1087df3..fbcee69 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getOpaque();
x = (String) mVh.getOpaque();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
index 0043451..2c56588 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.get();
x = (int) mVh.get();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
index 0162637..8fce69e 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.get();
x = (String) mVh.get();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
index b0c4631..ef530607 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetVolatileFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getVolatile(this);
x = (int) mVh.getVolatile(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
index 5cbbc08..64c0898 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetVolatileFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getVolatile(this);
x = (String) mVh.getVolatile(this);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
index 368ae69..939100c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getVolatile();
x = (int) mVh.getVolatile();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
index 3387a8d..728b199 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -54,7 +53,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getVolatile();
x = (String) mVh.getVolatile();
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
index 781e04f..bf5ef99 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final float FIELD_VALUE = 3.14f;
float mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
float x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (float) mVh.getAndAddAcquire(this, 2.17f);
x = (float) mVh.getAndAddAcquire(this, 2.17f);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
index 97f29ba..d15705e 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndAddAcquire(this, ~42);
x = (int) mVh.getAndAddAcquire(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
index e108f7f..222a60d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final float FIELD_VALUE = 3.14f;
static float sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
float x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (float) mVh.getAndAddAcquire(2.17f);
x = (float) mVh.getAndAddAcquire(2.17f);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
index d0ae322..7436476 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndAddAcquire(~42);
x = (int) mVh.getAndAddAcquire(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
index 1b80c40..cca97f4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddFieldLittleEndianFloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final float FIELD_VALUE = 3.14f;
float mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
float x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (float) mVh.getAndAdd(this, 2.17f);
x = (float) mVh.getAndAdd(this, 2.17f);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
index edacf181..170ee73 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndAdd(this, ~42);
x = (int) mVh.getAndAdd(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
index 0e86b0d..184f796 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final float FIELD_VALUE = 3.14f;
float mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
float x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (float) mVh.getAndAddRelease(this, 2.17f);
x = (float) mVh.getAndAddRelease(this, 2.17f);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
index 83446ff..7e75c44 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndAddRelease(this, ~42);
x = (int) mVh.getAndAddRelease(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
index c1f1e6f..39c386b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final float FIELD_VALUE = 3.14f;
static float sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
float x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (float) mVh.getAndAddRelease(2.17f);
x = (float) mVh.getAndAddRelease(2.17f);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
index 1b154a1..04ab531 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndAddRelease(~42);
x = (int) mVh.getAndAddRelease(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
index 7de128d..b71351f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final float FIELD_VALUE = 3.14f;
static float sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
float x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (float) mVh.getAndAdd(2.17f);
x = (float) mVh.getAndAdd(2.17f);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
index c9a0926..e3955c0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandaddStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndAdd(~42);
x = (int) mVh.getAndAdd(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
index fd9d9b1..adf05a6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseAndAcquire(this, ~42);
x = (int) mVh.getAndBitwiseAndAcquire(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
index c3c367f..4d657d9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseAndAcquire(~42);
x = (int) mVh.getAndBitwiseAndAcquire(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
index e073d28..dc64174 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseAnd(this, ~42);
x = (int) mVh.getAndBitwiseAnd(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
index ca78f5a..25d5631 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseAndRelease(this, ~42);
x = (int) mVh.getAndBitwiseAndRelease(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
index 599f186..de2d548 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseAndRelease(~42);
x = (int) mVh.getAndBitwiseAndRelease(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
index 71fc0ae..36544c6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseAnd(~42);
x = (int) mVh.getAndBitwiseAnd(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
index 8fc4eab..fb36d0c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseOrAcquire(this, ~42);
x = (int) mVh.getAndBitwiseOrAcquire(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
index 3368953..4194b12 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseOrAcquire(~42);
x = (int) mVh.getAndBitwiseOrAcquire(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
index 583a3a0..355c6e8 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseOr(this, ~42);
x = (int) mVh.getAndBitwiseOr(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
index 1592fa6..401079d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseOrRelease(this, ~42);
x = (int) mVh.getAndBitwiseOrRelease(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
index d496083..322dcbf 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseOrRelease(~42);
x = (int) mVh.getAndBitwiseOrRelease(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
index 87276a5..c982814 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseOr(~42);
x = (int) mVh.getAndBitwiseOr(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
index f7a372f..0b1cb32 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseXorAcquire(this, ~42);
x = (int) mVh.getAndBitwiseXorAcquire(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
index 22726fc..4737072 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseXorAcquire(~42);
x = (int) mVh.getAndBitwiseXorAcquire(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
index d071d6e..204cd70 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseXor(this, ~42);
x = (int) mVh.getAndBitwiseXor(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
index be2aa9c..b3ffed7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseXorRelease(this, ~42);
x = (int) mVh.getAndBitwiseXorRelease(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
index b0a7dcf..d0ab8de 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseXorRelease(~42);
x = (int) mVh.getAndBitwiseXorRelease(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
index c5f99de..b378b68 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndBitwiseXor(~42);
x = (int) mVh.getAndBitwiseXor(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
index 572e0c8..c7c66fe 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndSetAcquire(this, ~42);
x = (int) mVh.getAndSetAcquire(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
index 09be6d9..98d6bd7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAndSetAcquire(this, null);
x = (String) mVh.getAndSetAcquire(this, null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
index 4e0554a..206358f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndSetAcquire(~42);
x = (int) mVh.getAndSetAcquire(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
index 5491522..0532e73 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAndSetAcquire(null);
x = (String) mVh.getAndSetAcquire(null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
index a9303c6..f192d71 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndSet(this, ~42);
x = (int) mVh.getAndSet(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
index bd4703f..0a8909c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAndSet(this, null);
x = (String) mVh.getAndSet(this, null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
index d9aee00..bfcb0f4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndSetRelease(this, ~42);
x = (int) mVh.getAndSetRelease(this, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
index 2c79ca2..c6b0509 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAndSetRelease(this, null);
x = (String) mVh.getAndSetRelease(this, null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
index ceff8163..45a01ed 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndSetRelease(~42);
x = (int) mVh.getAndSetRelease(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
index 9b83504..3047281 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAndSetRelease(null);
x = (String) mVh.getAndSetRelease(null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
index 638da6f..6f1f1a0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (int) mVh.getAndSet(~42);
x = (int) mVh.getAndSet(~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
index 25d41141..c4d279f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleGetandsetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
x = (String) mVh.getAndSet(null);
x = (String) mVh.getAndSet(null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
index 64ea9f3..c4f6005 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,9 +33,9 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetArrayLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int ELEMENT_VALUE = 42;
- int[] mArray = { ELEMENT_VALUE };
+ int[] mArray = {ELEMENT_VALUE};
VarHandle mVh;
public VarHandleSetArrayLittleEndianIntPerfTest() throws Throwable {
@@ -54,7 +53,7 @@
public void run() {
int[] a = mArray;
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(a, 0, ~42);
mVh.set(a, 0, ~42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
index 989d682..a6858c2 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,9 +33,9 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetArrayLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String ELEMENT_VALUE = "qwerty";
- String[] mArray = { ELEMENT_VALUE };
+ String[] mArray = {ELEMENT_VALUE};
VarHandle mVh;
public VarHandleSetArrayLittleEndianStringPerfTest() throws Throwable {
@@ -54,7 +53,7 @@
public void run() {
String[] a = mArray;
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(a, 0, null);
mVh.set(a, 0, null);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
index 9d6d6b8..a994cbe 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
@@ -13,52 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
import java.nio.ByteOrder;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetByteArrayViewBigEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int VALUE = 42;
- byte[] mArray1 = { (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE };
- byte[] mArray2 = { (byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE };
+ byte[] mArray1 = {
+ (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE
+ };
+ byte[] mArray2 = {(byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE};
VarHandle mVh;
public VarHandleSetByteArrayViewBigEndianIntPerfTest() throws Throwable {
mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
- }
+ }
@After
public void teardown() {
if (!Arrays.equals(mArray2, mArray1)) {
- throw new RuntimeException("array has unexpected values: " +
- mArray2[0] + " " + mArray2[1] + " " + mArray2[2] + " " + mArray2[3]);
+ throw new RuntimeException(
+ "array has unexpected values: "
+ + mArray2[0]
+ + " "
+ + mArray2[1]
+ + " "
+ + mArray2[2]
+ + " "
+ + mArray2[3]);
}
}
@Test
public void run() {
byte[] a = mArray2;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(a, 0, VALUE);
mVh.set(a, 0, VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
index e8c3fa3..65412ec 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
@@ -13,52 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
import java.nio.ByteOrder;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetByteArrayViewLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int VALUE = 42;
- byte[] mArray1 = { (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24) };
- byte[] mArray2 = { (byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24) };
+ byte[] mArray1 = {
+ (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24)
+ };
+ byte[] mArray2 = {(byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24)};
VarHandle mVh;
public VarHandleSetByteArrayViewLittleEndianIntPerfTest() throws Throwable {
mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
- }
+ }
@After
public void teardown() {
if (!Arrays.equals(mArray2, mArray1)) {
- throw new RuntimeException("array has unexpected values: " +
- mArray2[0] + " " + mArray2[1] + " " + mArray2[2] + " " + mArray2[3]);
+ throw new RuntimeException(
+ "array has unexpected values: "
+ + mArray2[0]
+ + " "
+ + mArray2[1]
+ + " "
+ + mArray2[2]
+ + " "
+ + mArray2[3]);
}
}
@Test
public void run() {
byte[] a = mArray2;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(a, 0, VALUE);
mVh.set(a, 0, VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
index 08294c0..573b0ff 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(this, FIELD_VALUE);
mVh.set(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
index 1e8a5bf..fe3c0fc 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(this, FIELD_VALUE);
mVh.set(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
index 2e5fb18..f398899 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetOpaqueFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setOpaque(this, FIELD_VALUE);
mVh.setOpaque(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
index 86a771f..7493120 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetOpaqueFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setOpaque(this, FIELD_VALUE);
mVh.setOpaque(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
index 903b310..5e73269 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setOpaque(FIELD_VALUE);
mVh.setOpaque(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
index 63cf7d2..9a217d1 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setOpaque(FIELD_VALUE);
mVh.setOpaque(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
index d1a358d..1ce2270 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setRelease(this, FIELD_VALUE);
mVh.setRelease(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
index b658324..ed84528 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetReleaseFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setRelease(this, FIELD_VALUE);
mVh.setRelease(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
index 47cb779..aeb9640 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setRelease(FIELD_VALUE);
mVh.setRelease(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
index e48374e..8959a0c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setRelease(FIELD_VALUE);
mVh.setRelease(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
index 0470d67..4007722 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(FIELD_VALUE);
mVh.set(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
index 00abb0b..7323158 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.set(FIELD_VALUE);
mVh.set(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
index c66b23b..f4119c2 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetVolatileFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setVolatile(this, FIELD_VALUE);
mVh.setVolatile(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
index 1b36450..9b9c261 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetVolatileFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setVolatile(this, FIELD_VALUE);
mVh.setVolatile(this, FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
index 75f9274..f125384 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
int x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setVolatile(FIELD_VALUE);
mVh.setVolatile(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
index 8289d4f..2ad605d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -53,7 +52,7 @@
@Test
public void run() {
String x;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mVh.setVolatile(FIELD_VALUE);
mVh.setVolatile(FIELD_VALUE);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
index 9fac842..5ef3bf0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetAcquire(this, mField, ~42);
success = mVh.weakCompareAndSetAcquire(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
index 2f60127..0c4ed66 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetAcquire(this, mField, null);
success = mVh.weakCompareAndSetAcquire(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
index 4efbd3e..db6bd24 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetAcquire(sField, ~42);
success = mVh.weakCompareAndSetAcquire(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
index 099640c..d2b0bf7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
- public VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ public VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
}
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetAcquire(sField, null);
success = mVh.weakCompareAndSetAcquire(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
index ce8f0f0..3cd5ae6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSet(this, mField, ~42);
success = mVh.weakCompareAndSet(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
index c4119dc..6ddfc25 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSet(this, mField, null);
success = mVh.weakCompareAndSet(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
index abd981c..375f0bc 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetPlain(this, mField, ~42);
success = mVh.weakCompareAndSetPlain(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
index c71e65f..7e2492a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetPlain(this, mField, null);
success = mVh.weakCompareAndSetPlain(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
index f3c8f3a..190118c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetPlain(sField, ~42);
success = mVh.weakCompareAndSetPlain(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
index 5c943a4..484ba1b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetPlain(sField, null);
success = mVh.weakCompareAndSetPlain(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
index 1755a15..80e4e15 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
int mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetRelease(this, mField, ~42);
success = mVh.weakCompareAndSetRelease(this, mField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
index 77175b0..fa26c59 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
String mField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetRelease(this, mField, null);
success = mVh.weakCompareAndSetRelease(this, mField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
index 985519e..16bf2a20 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetRelease(sField, ~42);
success = mVh.weakCompareAndSetRelease(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
index 69e6ca7..e1716de 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
- public VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest() throws Throwable {
+ public VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest()
+ throws Throwable {
mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
}
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSetRelease(sField, null);
success = mVh.weakCompareAndSetRelease(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
index 88df5ff..dc6f2ad 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final int FIELD_VALUE = 42;
static int sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSet(sField, ~42);
success = mVh.weakCompareAndSet(sField, 42);
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
index c296f668..d1096c6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest {
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final String FIELD_VALUE = "qwerty";
static String sField = FIELD_VALUE;
VarHandle mVh;
@@ -46,7 +44,7 @@
@Test
public void run() {
boolean success;
- final BenchmarkState state = mBenchmarkRule.getState();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
success = mVh.weakCompareAndSet(sField, null);
success = mVh.weakCompareAndSet(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
index a43569a..4b4bc60 100755
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
@@ -42,7 +42,7 @@
return ''.join(c for c in word.title() if not c == '_')
-LOOP ="final BenchmarkState state = mBenchmarkRule.getState();\n while (state.keepRunning())"
+LOOP ="BenchmarkState state = mPerfStatusReporter.getBenchmarkState();\n while (state.keepRunning())"
class Benchmark:
def __init__(self, code, static, vartype, flavour, klass, method, memloc,
@@ -158,10 +158,10 @@
VH_IMPORTS = """
package android.libcore.varhandles;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
-import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
@@ -179,7 +179,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class {name} {{
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final {vartype} FIELD_VALUE = {value1};
{static_kwd}{vartype} {static_prefix}Field = FIELD_VALUE;
VarHandle mVh;
@@ -273,7 +273,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class {name} {{
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final {vartype} ELEMENT_VALUE = {value1};
{vartype}[] mArray = {{ ELEMENT_VALUE }};
VarHandle mVh;
@@ -324,7 +324,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class {name} {{
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
static final {vartype} VALUE = {value1};
byte[] mArray1 = {value1_byte_array};
byte[] mArray2 = {value2_byte_array};
@@ -375,7 +375,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class {name} {{
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
Field mField;
{static_kwd}{vartype} {static_prefix}Value;
@@ -407,7 +407,7 @@
@RunWith(AndroidJUnit4.class)
@LargeTest
public class {name} {{
- @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
long mOffset;
public {static_kwd}{vartype} {static_prefix}Value = {value1};
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index 16c2fd4..a0bf78f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -25,10 +25,7 @@
]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.job"}
- ]
+ "name": "FrameworksServicesTests_com_android_server_job"
},
{
"name": "CtsHostsideNetworkPolicyTests",
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index dd0d1b6..f56c14d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -21,10 +21,7 @@
"name": "CtsUsageStatsTestCases"
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.usage"}
- ]
+ "name": "FrameworksServicesTests_com_android_server_usage"
}
]
}
diff --git a/cmds/screencap/Android.bp b/cmds/screencap/Android.bp
index c009c1f..16026ec 100644
--- a/cmds/screencap/Android.bp
+++ b/cmds/screencap/Android.bp
@@ -17,6 +17,7 @@
"libutils",
"libbinder",
"libjnigraphics",
+ "libhwui",
"libui",
"libgui",
],
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 01b20f4..12de82a 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -15,36 +15,28 @@
*/
#include <android/bitmap.h>
+#include <android/graphics/bitmap.h>
#include <android/gui/DisplayCaptureArgs.h>
#include <binder/ProcessState.h>
#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <linux/fb.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-
-#include <android/bitmap.h>
-
-#include <binder/ProcessState.h>
-
#include <ftl/concat.h>
#include <ftl/optional.h>
+#include <getopt.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
-
+#include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <system/graphics.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
-#include <system/graphics.h>
-
using namespace android;
#define COLORSPACE_UNKNOWN 0
@@ -85,11 +77,12 @@
};
}
-static const struct option LONG_OPTIONS[] = {
- {"png", no_argument, nullptr, 'p'},
- {"help", no_argument, nullptr, 'h'},
- {"hint-for-seamless", no_argument, nullptr, LongOpts::HintForSeamless},
- {0, 0, 0, 0}};
+static const struct option LONG_OPTIONS[] = {{"png", no_argument, nullptr, 'p'},
+ {"jpeg", no_argument, nullptr, 'j'},
+ {"help", no_argument, nullptr, 'h'},
+ {"hint-for-seamless", no_argument, nullptr,
+ LongOpts::HintForSeamless},
+ {0, 0, 0, 0}};
static int32_t flinger2bitmapFormat(PixelFormat f)
{
@@ -170,10 +163,11 @@
return 0;
}
-status_t saveImage(const char* fn, bool png, const ScreenCaptureResults& captureResults) {
+status_t saveImage(const char* fn, std::optional<AndroidBitmapCompressFormat> format,
+ const ScreenCaptureResults& captureResults) {
void* base = nullptr;
ui::Dataspace dataspace = captureResults.capturedDataspace;
- sp<GraphicBuffer> buffer = captureResults.buffer;
+ const sp<GraphicBuffer>& buffer = captureResults.buffer;
status_t result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
@@ -188,22 +182,48 @@
return 1;
}
+ void* gainmapBase = nullptr;
+ sp<GraphicBuffer> gainmap = captureResults.optionalGainMap;
+
+ if (gainmap) {
+ result = gainmap->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &gainmapBase);
+ if (gainmapBase == nullptr || result != NO_ERROR) {
+ fprintf(stderr, "Failed to capture gainmap with error code (%d)\n", result);
+ gainmapBase = nullptr;
+ // Fall-through: just don't attempt to write the gainmap
+ }
+ }
+
int fd = -1;
if (fn == nullptr) {
fd = dup(STDOUT_FILENO);
if (fd == -1) {
fprintf(stderr, "Error writing to stdout. (%s)\n", strerror(errno));
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
return 1;
}
} else {
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd == -1) {
fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
return 1;
}
}
- if (png) {
+ if (format) {
AndroidBitmapInfo info;
info.format = flinger2bitmapFormat(buffer->getPixelFormat());
info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
@@ -211,16 +231,31 @@
info.height = buffer->getHeight();
info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
- int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
- ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
+ int result;
+
+ if (gainmapBase) {
+ result = ABitmap_compressWithGainmap(&info, static_cast<ADataSpace>(dataspace), base,
+ gainmapBase, captureResults.hdrSdrRatio, *format,
+ 100, &fd,
+ [](void* fdPtr, const void* data,
+ size_t size) -> bool {
+ int bytesWritten =
+ write(*static_cast<int*>(fdPtr), data,
+ size);
+ return bytesWritten == size;
+ });
+ } else {
+ result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base, *format,
+ 100, &fd,
[](void* fdPtr, const void* data, size_t size) -> bool {
int bytesWritten = write(*static_cast<int*>(fdPtr),
data, size);
return bytesWritten == size;
});
+ }
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
- fprintf(stderr, "Failed to compress PNG (error code: %d)\n", result);
+ fprintf(stderr, "Failed to compress (error code: %d)\n", result);
}
if (fn != NULL) {
@@ -245,6 +280,14 @@
}
close(fd);
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
+
return 0;
}
@@ -262,13 +305,17 @@
gui::CaptureArgs captureArgs;
const char* pname = argv[0];
bool png = false;
+ bool jpeg = false;
bool all = false;
int c;
- while ((c = getopt_long(argc, argv, "aphd:", LONG_OPTIONS, nullptr)) != -1) {
+ while ((c = getopt_long(argc, argv, "apjhd:", LONG_OPTIONS, nullptr)) != -1) {
switch (c) {
case 'p':
png = true;
break;
+ case 'j':
+ jpeg = true;
+ break;
case 'd': {
errno = 0;
char* end = nullptr;
@@ -325,6 +372,14 @@
baseName = filename.substr(0, filename.size()-4);
suffix = ".png";
png = true;
+ } else if (filename.ends_with(".jpeg")) {
+ baseName = filename.substr(0, filename.size() - 5);
+ suffix = ".jpeg";
+ jpeg = true;
+ } else if (filename.ends_with(".jpg")) {
+ baseName = filename.substr(0, filename.size() - 4);
+ suffix = ".jpg";
+ jpeg = true;
} else {
baseName = filename;
}
@@ -350,6 +405,20 @@
}
}
+ if (png && jpeg) {
+ fprintf(stderr, "Ambiguous file type");
+ return 1;
+ }
+
+ std::optional<AndroidBitmapCompressFormat> format = std::nullopt;
+
+ if (png) {
+ format = ANDROID_BITMAP_COMPRESS_FORMAT_PNG;
+ } else if (jpeg) {
+ format = ANDROID_BITMAP_COMPRESS_FORMAT_JPEG;
+ captureArgs.attachGainmap = true;
+ }
+
// setThreadPoolMaxThreadCount(0) actually tells the kernel it's
// not allowed to spawn any additional threads, but we still spawn
// a binder thread from userspace when we call startThreadPool().
@@ -385,7 +454,7 @@
if (!filename.empty()) {
fn = filename.c_str();
}
- if (const status_t saveImageStatus = saveImage(fn, png, result) != 0) {
+ if (const status_t saveImageStatus = saveImage(fn, format, result) != 0) {
fprintf(stderr, "Saving image failed.\n");
return saveImageStatus;
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 5cdc57a..520c7d1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6396,6 +6396,7 @@
method public android.graphics.drawable.Icon getLargeIcon();
method @Nullable public android.content.LocusId getLocusId();
method public CharSequence getSettingsText();
+ method @FlaggedApi("android.app.api_rich_ongoing") @Nullable public String getShortCriticalText();
method public String getShortcutId();
method public android.graphics.drawable.Icon getSmallIcon();
method public String getSortKey();
@@ -6719,6 +6720,7 @@
method @NonNull public android.app.Notification.Builder setPublicVersion(android.app.Notification);
method @NonNull public android.app.Notification.Builder setRemoteInputHistory(CharSequence[]);
method @NonNull public android.app.Notification.Builder setSettingsText(CharSequence);
+ method @FlaggedApi("android.app.api_rich_ongoing") @NonNull public android.app.Notification.Builder setShortCriticalText(@Nullable String);
method @NonNull public android.app.Notification.Builder setShortcutId(String);
method @NonNull public android.app.Notification.Builder setShowWhen(boolean);
method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int);
@@ -19168,7 +19170,7 @@
method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
method @NonNull public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
- method @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys();
+ method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
@@ -19211,7 +19213,7 @@
field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateSensorOrientationMap> INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP;
- field @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES;
@@ -20081,14 +20083,14 @@
public final class ExtensionSessionConfiguration {
ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void clearColorSpace();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") @Nullable public android.graphics.ColorSpace getColorSpace();
+ method public void clearColorSpace();
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
method @NonNull public java.util.concurrent.Executor getExecutor();
method public int getExtension();
method @NonNull public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
method @Nullable public android.hardware.camera2.params.OutputConfiguration getPostviewOutputConfiguration();
method @NonNull public android.hardware.camera2.CameraExtensionSession.StateCallback getStateCallback();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
+ method public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
method public void setPostviewOutputConfiguration(@Nullable android.hardware.camera2.params.OutputConfiguration);
}
@@ -50805,6 +50807,7 @@
method public android.view.Display.HdrCapabilities getHdrCapabilities();
method public float getHdrSdrRatio();
method @Deprecated public int getHeight();
+ method @FlaggedApi("com.android.server.display.feature.flags.highest_hdr_sdr_ratio_api") public float getHighestHdrSdrRatio();
method @Deprecated public void getMetrics(android.util.DisplayMetrics);
method public android.view.Display.Mode getMode();
method public String getName();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index df707d1..1e94c2f 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -673,8 +673,8 @@
method @Nullable public android.content.pm.PackageInfo getCurrentWebViewPackage();
method @Nullable public String getCurrentWebViewPackageName();
method @FlaggedApi("android.webkit.update_service_v2") @NonNull public android.webkit.WebViewProviderInfo getDefaultWebViewPackage();
- method @Nullable public static android.webkit.WebViewUpdateManager getInstance();
- method @NonNull @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.QUERY_ALL_PACKAGES}) public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+ method @NonNull public static android.webkit.WebViewUpdateManager getInstance();
+ method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
method @NonNull public android.webkit.WebViewProviderResponse waitForAndGetProvider();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fb425a9..9c807af 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4972,12 +4972,12 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class CameraOutputSurface {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public int getColorSpace();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public long getDynamicRangeProfile();
+ method public int getColorSpace();
+ method public long getDynamicRangeProfile();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int getImageFormat();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.util.Size getSize();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.view.Surface getSurface();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setDynamicRangeProfile(long);
+ method public void setDynamicRangeProfile(long);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class CharacteristicsMap {
@@ -4987,7 +4987,7 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionConfiguration {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public ExtensionConfiguration(int, int, @NonNull java.util.List<android.hardware.camera2.extension.ExtensionOutputConfiguration>, @Nullable android.hardware.camera2.CaptureRequest);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(int);
+ method public void setColorSpace(int);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionOutputConfiguration {
@@ -18769,7 +18769,7 @@
public final class WebViewUpdateService {
method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
method public static String getCurrentWebViewPackageName();
- method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+ method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4fc7076..caf6992 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2321,7 +2321,7 @@
}
public final class BugreportParams {
- field @FlaggedApi("android.os.bugreport_mode_max_value") public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
+ field public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
}
public class Build {
diff --git a/core/java/android/app/CameraCompatTaskInfo.java b/core/java/android/app/CameraCompatTaskInfo.java
index 53eddbe..432a0da 100644
--- a/core/java/android/app/CameraCompatTaskInfo.java
+++ b/core/java/android/app/CameraCompatTaskInfo.java
@@ -36,20 +36,36 @@
public static final int CAMERA_COMPAT_FREEFORM_NONE = 0;
/**
- * The value to use when portrait camera compat treatment should be applied to a windowed task.
+ * The value to use when camera compat treatment should be applied to an activity requesting
+ * portrait orientation, while a device is in landscape. Applies only to freeform tasks.
*/
- public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT = 1;
+ public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE = 1;
/**
- * The value to use when landscape camera compat treatment should be applied to a windowed task.
+ * The value to use when camera compat treatment should be applied to an activity requesting
+ * landscape orientation, while a device is in landscape. Applies only to freeform tasks.
*/
- public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE = 2;
+ public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE = 2;
+
+ /**
+ * The value to use when camera compat treatment should be applied to an activity requesting
+ * portrait orientation, while a device is in portrait. Applies only to freeform tasks.
+ */
+ public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT = 3;
+
+ /**
+ * The value to use when camera compat treatment should be applied to an activity requesting
+ * landscape orientation, while a device is in portrait. Applies only to freeform tasks.
+ */
+ public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT = 4;
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "CAMERA_COMPAT_FREEFORM_" }, value = {
CAMERA_COMPAT_FREEFORM_NONE,
- CAMERA_COMPAT_FREEFORM_PORTRAIT,
- CAMERA_COMPAT_FREEFORM_LANDSCAPE,
+ CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE,
+ CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE,
+ CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT,
+ CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT,
})
public @interface FreeformCameraCompatMode {}
@@ -143,8 +159,14 @@
@FreeformCameraCompatMode int freeformCameraCompatMode) {
return switch (freeformCameraCompatMode) {
case CAMERA_COMPAT_FREEFORM_NONE -> "inactive";
- case CAMERA_COMPAT_FREEFORM_PORTRAIT -> "portrait";
- case CAMERA_COMPAT_FREEFORM_LANDSCAPE -> "landscape";
+ case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE ->
+ "app-portrait-device-landscape";
+ case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE ->
+ "app-landscape-device-landscape";
+ case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT ->
+ "app-portrait-device-portrait";
+ case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT ->
+ "app-landscape-device-portrait";
default -> throw new AssertionError(
"Unexpected camera compat mode: " + freeformCameraCompatMode);
};
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 45852c7..93a9489 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -2408,9 +2408,9 @@
* @hide
*/
@android.ravenwood.annotation.RavenwoodKeep
- public final void basicInit(Context context) {
- mInstrContext = context;
- mAppContext = context;
+ public final void basicInit(Context instrContext, Context appContext) {
+ mInstrContext = instrContext;
+ mAppContext = appContext;
}
/** @hide */
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7a36fbb..81d2c89 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1281,6 +1281,15 @@
public static final String EXTRA_BIG_TEXT = "android.bigText";
/**
+ * {@link #extras} key: very short text summarizing the most critical information contained in
+ * the notification.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ public static final String EXTRA_SHORT_CRITICAL_TEXT = "android.shortCriticalText";
+
+ /**
* {@link #extras} key: this is the resource ID of the notification's main small icon, as
* supplied to {@link Builder#setSmallIcon(int)}.
*
@@ -4050,6 +4059,17 @@
return String.join("|", defaultStrings);
}
+
+ /**
+ * Returns the very short text summarizing the most critical information contained in the
+ * notification, or null if this field was not set.
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ public String getShortCriticalText() {
+ return extras.getString(EXTRA_SHORT_CRITICAL_TEXT);
+ }
+
/**
* @hide
*/
@@ -4991,6 +5011,18 @@
}
/**
+ * Sets a very short string summarizing the most critical information contained in the
+ * notification. Suggested max length is 5 characters, and there is no guarantee how much or
+ * how little of this text will be shown.
+ */
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ @NonNull
+ public Builder setShortCriticalText(@Nullable String shortCriticalText) {
+ mN.extras.putString(EXTRA_SHORT_CRITICAL_TEXT, shortCriticalText);
+ return this;
+ }
+
+ /**
* Set the progress this notification represents.
*
* The platform template will represent this using a {@link ProgressBar}.
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 32e9542..4a2b016 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -55,7 +55,9 @@
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -100,6 +102,11 @@
@FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
public static final String RECS_ID = "android.app.recs";
+ /** @hide */
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final ArrayList<String> SYSTEM_RESERVED_IDS = new ArrayList<>(
+ List.of(NEWS_ID, SOCIAL_MEDIA_ID, PROMOTIONS_ID, RECS_ID));
+
/**
* The formatter used by the system to create an id for notification
* channels when it automatically creates conversation channels on behalf of an app. The format
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e44e776..5147f12 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -104,6 +104,7 @@
import android.devicelock.DeviceLockFrameworkInitializer;
import android.graphics.fonts.FontManager;
import android.hardware.ConsumerIrManager;
+import android.hardware.ISensorPrivacyManager;
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
@@ -707,8 +708,12 @@
registerService(Context.SENSOR_PRIVACY_SERVICE, SensorPrivacyManager.class,
new CachedServiceFetcher<SensorPrivacyManager>() {
@Override
- public SensorPrivacyManager createService(ContextImpl ctx) {
- return SensorPrivacyManager.getInstance(ctx);
+ public SensorPrivacyManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.SENSOR_PRIVACY_SERVICE);
+ return SensorPrivacyManager.getInstance(
+ ctx, ISensorPrivacyManager.Stub.asInterface(b));
}});
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index c7b0be7..46567c4 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -1107,7 +1107,7 @@
/**
* Called to notify the state of operations that can be unsafe to execute has changed.
*
- * <p><b>Note:/b> notice that the operation safety state might change between the time this
+ * <p><b>Note:</b> notice that the operation safety state might change between the time this
* callback is received and the operation's method on {@link DevicePolicyManager} is called, so
* calls to the latter could still throw a {@link UnsafeStateException} even when this method
* is called with {@code isSafe} as {@code true}
diff --git a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
index 085e0a4..a23f842 100644
--- a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
+++ b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
@@ -37,6 +37,8 @@
public class AppFunctionStaticMetadataHelper {
public static final String STATIC_SCHEMA_TYPE = "AppFunctionStaticMetadata";
public static final String STATIC_PROPERTY_ENABLED_BY_DEFAULT = "enabledByDefault";
+ public static final String STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS =
+ "restrictCallersWithExecuteAppFunctions";
public static final String APP_FUNCTION_STATIC_NAMESPACE = "app_functions";
public static final String PROPERTY_FUNCTION_ID = "functionId";
diff --git a/core/java/android/app/jank/flags.aconfig b/core/java/android/app/jank/flags.aconfig
new file mode 100644
index 0000000..5657f7e
--- /dev/null
+++ b/core/java/android/app/jank/flags.aconfig
@@ -0,0 +1,16 @@
+package: "android.app.jank"
+container: "system"
+
+flag {
+ name: "detailed_app_jank_metrics_api"
+ namespace: "system_performance"
+ description: "Control the API portion of Detailed Application Jank Metrics"
+ bug: "366264614"
+}
+
+flag {
+ name: "detailed_app_jank_metrics_logging_enabled"
+ namespace: "system_performance"
+ description: "Controls whether the system will log frame metrics related to app jank"
+ bug: "366265225"
+}
\ No newline at end of file
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 60d1b0d..e895d7b 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -3141,14 +3141,6 @@
for (int i = 0; i < N; i++) {
mUriRelativeFilterGroups.add(new UriRelativeFilterGroup(source));
}
- if (source.dataAvail() > 0) {
- Log.e(TAG, "Parcel data not fully consumed after completed reading"
- + " UriRelativeFilterGroup data");
- }
- }
- if (source.dataAvail() > 0) {
- Log.e(TAG, "Parcel data not fully consumed when unparceling intent filter",
- new Exception());
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 26bb6e4..fb2655c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8842,6 +8842,7 @@
try {
ParsedPackage pp = parser2.parsePackage(apkFile, parserFlags, false);
+ pp.hideAsFinal();
return PackageInfoCommonUtils.generate(pp, flagsBits, UserHandle.myUserId());
} catch (PackageParserException e) {
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 7c2edd7..139ff65 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -285,4 +285,12 @@
namespace: "package_manager_service"
description: "Feature flag to enable the feature to retrieve package info without installation with a file descriptor."
bug: "340879905"
+}
+
+flag {
+ name: "get_packages_from_launcher_apps"
+ namespace: "package_manager_service"
+ description: "Feature flag to provide the new methods within launcher apps class to get packages."
+ bug: "363324203"
+ is_fixed_read_only: true
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 4cdaaddd..a4c0e87 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -797,7 +797,7 @@
public void setSensorPrivacy(@Sensors.Sensor int sensor,
boolean enable) {
setSensorPrivacy(resolveSourceFromCurrentContext(), sensor, enable,
- UserHandle.USER_CURRENT);
+ mContext.getUserId());
}
private @Sources.Source int resolveSourceFromCurrentContext() {
@@ -837,6 +837,8 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
boolean enable) {
+ // TODO(b/348510106): Replace USER_CURRENT with Context user and fix any tests that may be
+ // affected.
setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT);
}
@@ -894,7 +896,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
@Sensors.Sensor int sensor, boolean enable) {
- setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT);
+ setSensorPrivacyForProfileGroup(source , sensor, enable, mContext.getUserId());
}
/**
@@ -950,7 +952,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void suppressSensorPrivacyReminders(int sensor,
boolean suppress) {
- suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT);
+ suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId());
}
/**
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 056ca93..7a8a16f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -567,7 +567,6 @@
* @see #INFO_SESSION_CONFIGURATION_QUERY_VERSION
*/
@NonNull
- @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
public List<CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys() {
if (mAvailableSessionCharacteristicsKeys != null) {
return mAvailableSessionCharacteristicsKeys;
@@ -5210,7 +5209,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
public static final Key<Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION =
new Key<Integer>("android.info.sessionConfigurationQueryVersion", int.class);
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 6a7ee7f..d40b2e3 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -29,6 +29,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.ActivityManager;
+import android.app.CameraCompatTaskInfo;
import android.app.TaskInfo;
import android.app.compat.CompatChanges;
import android.companion.virtual.VirtualDeviceManager;
@@ -1586,12 +1587,13 @@
context.getSystemService(ActivityManager.class);
for (ActivityManager.AppTask appTask : activityManager.getAppTasks()) {
final TaskInfo taskInfo = appTask.getTaskInfo();
- if (taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode
- != 0
+ final int freeformCameraCompatMode =
+ taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode;
+ if (freeformCameraCompatMode != 0
&& taskInfo.topActivity != null
&& taskInfo.topActivity.getPackageName().equals(packageName)) {
// WindowManager has requested rotation override.
- return ICameraService.ROTATION_OVERRIDE_ROTATION_ONLY;
+ return getRotationOverrideForCompatFreeform(freeformCameraCompatMode);
}
}
}
@@ -1613,6 +1615,19 @@
: ICameraService.ROTATION_OVERRIDE_NONE;
}
+ private static int getRotationOverrideForCompatFreeform(
+ @CameraCompatTaskInfo.FreeformCameraCompatMode int freeformCameraCompatMode) {
+ // Only rotate-and-crop if the app and device orientations do not match.
+ if (freeformCameraCompatMode
+ == CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT
+ || freeformCameraCompatMode
+ == CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE) {
+ return ICameraService.ROTATION_OVERRIDE_ROTATION_ONLY;
+ } else {
+ return ICameraService.ROTATION_OVERRIDE_NONE;
+ }
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
index 001b794..32139b8 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
+++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
@@ -107,7 +107,6 @@
* {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
* unless specified by CameraOutputSurface.setDynamicRangeProfile.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public @DynamicRangeProfiles.Profile long getDynamicRangeProfile() {
return mOutputSurface.dynamicRangeProfile;
}
@@ -118,7 +117,6 @@
* unless specified by CameraOutputSurface.setColorSpace.
*/
@SuppressLint("MethodNameUnits")
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public int getColorSpace() {
return mOutputSurface.colorSpace;
}
@@ -128,7 +126,6 @@
* will be {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
* unless explicitly set using this method.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setDynamicRangeProfile(
@DynamicRangeProfiles.Profile long dynamicRangeProfile) {
mOutputSurface.dynamicRangeProfile = dynamicRangeProfile;
diff --git a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
index 84b7a7f..32de1ce 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
@@ -83,7 +83,6 @@
* The default will be -1, indicating an unspecified ColorSpace,
* unless explicitly set using this method.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setColorSpace(int colorSpace) {
mColorSpace = colorSpace;
}
@@ -98,11 +97,7 @@
ret.sessionTemplateId = mSessionTemplateId;
ret.sessionType = mSessionType;
ret.outputConfigs = new ArrayList<>(mOutputs.size());
- if (Flags.extension10Bit()) {
- ret.colorSpace = mColorSpace;
- } else {
- ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
- }
+ ret.colorSpace = mColorSpace;
for (ExtensionOutputConfiguration outputConfig : mOutputs) {
ret.outputConfigs.add(outputConfig.getOutputConfig());
}
diff --git a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
index 3a67d61..8a47430 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
@@ -80,11 +80,7 @@
config.outputId = new OutputConfigId();
config.outputId.id = mOutputConfigId;
config.surfaceGroupId = mSurfaceGroupId;
- if (Flags.extension10Bit()) {
- config.dynamicRangeProfile = surface.getDynamicRangeProfile();
- } else {
- config.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
- }
+ config.dynamicRangeProfile = surface.getDynamicRangeProfile();
}
@Nullable CameraOutputConfig getOutputConfig() {
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 2e1e90c..323712d 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -148,7 +148,7 @@
for (OutputConfiguration c : config.getOutputConfigurations()) {
if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) {
- if (Flags.extension10Bit() && Flags.cameraExtensionsCharacteristicsGet()) {
+ if (Flags.cameraExtensionsCharacteristicsGet()) {
DynamicRangeProfiles dynamicProfiles = extensionChars.get(
config.getExtension(),
CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES);
@@ -190,9 +190,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (int format : supportedCaptureOutputFormats.toArray()) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
@@ -359,22 +357,20 @@
cameraOutput.setTimestampBase(OutputConfiguration.TIMESTAMP_BASE_SENSOR);
cameraOutput.setReadoutTimestampEnabled(false);
cameraOutput.setPhysicalCameraId(output.physicalCameraId);
- if (Flags.extension10Bit()) {
- boolean validDynamicRangeProfile = false;
- for (long profile = DynamicRangeProfiles.STANDARD;
- profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
- if (output.dynamicRangeProfile == profile) {
- validDynamicRangeProfile = true;
- break;
- }
+ boolean validDynamicRangeProfile = false;
+ for (long profile = DynamicRangeProfiles.STANDARD;
+ profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
+ if (output.dynamicRangeProfile == profile) {
+ validDynamicRangeProfile = true;
+ break;
}
- if (validDynamicRangeProfile) {
- cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
- } else {
- Log.e(TAG, "Extension configured dynamic range profile "
- + output.dynamicRangeProfile
- + " is not valid, using default DynamicRangeProfile.STANDARD");
- }
+ }
+ if (validDynamicRangeProfile) {
+ cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
+ } else {
+ Log.e(TAG, "Extension configured dynamic range profile "
+ + output.dynamicRangeProfile
+ + " is not valid, using default DynamicRangeProfile.STANDARD");
}
outputList.add(cameraOutput);
mCameraConfigMap.put(cameraOutput.getSurface(), output);
@@ -390,15 +386,13 @@
SessionConfiguration sessionConfiguration = new SessionConfiguration(sessionType,
outputList, new CameraExtensionUtils.HandlerExecutor(mHandler),
new SessionStateHandler());
- if (Flags.extension10Bit()) {
- if (sessionConfig.colorSpace >= 0
- && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
- sessionConfiguration.setColorSpace(
- ColorSpace.Named.values()[sessionConfig.colorSpace]);
- } else {
- Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
- + " is not valid, using default unspecified color space");
- }
+ if (sessionConfig.colorSpace >= 0
+ && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
+ sessionConfiguration.setColorSpace(
+ ColorSpace.Named.values()[sessionConfig.colorSpace]);
+ } else {
+ Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
+ + " is not valid, using default unspecified color space");
}
if ((sessionConfig.sessionParameter != null) &&
(!sessionConfig.sessionParameter.isEmpty())) {
@@ -459,16 +453,11 @@
ret.size.height = surfaceSize.getHeight();
ret.imageFormat = SurfaceUtils.getSurfaceFormat(s);
- if (Flags.extension10Bit()) {
- ret.dynamicRangeProfile = o.getDynamicRangeProfile();
- ColorSpace colorSpace = o.getColorSpace();
- if (colorSpace != null) {
- ret.colorSpace = colorSpace.getId();
- } else {
- ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
- }
+ ret.dynamicRangeProfile = o.getDynamicRangeProfile();
+ ColorSpace colorSpace = o.getColorSpace();
+ if (colorSpace != null) {
+ ret.colorSpace = colorSpace.getId();
} else {
- ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
}
} else {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index a10e250..ab4ff72 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -208,10 +208,6 @@
}
public void onOutputSurface(Surface surface, int format) throws RemoteException {
- if (!Flags.extension10Bit() && format != ImageFormat.JPEG) {
- Log.e(TAG, "Unsupported output format: " + format);
- return;
- }
CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(surface);
mCaptureFormat = surfaceInfo.mFormat;
mOutputSurface = surface;
@@ -221,10 +217,6 @@
public void onPostviewOutputSurface(Surface surface) throws RemoteException {
CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
CameraExtensionUtils.querySurface(surface);
- if (!Flags.extension10Bit() && postviewSurfaceInfo.mFormat != ImageFormat.JPEG) {
- Log.e(TAG, "Unsupported output format: " + postviewSurfaceInfo.mFormat);
- return;
- }
mPostviewFormat = postviewSurfaceInfo.mFormat;
mPostviewOutputSurface = surface;
initializePostviewPipeline();
@@ -240,10 +232,6 @@
}
public void onImageFormatUpdate(int format) throws RemoteException {
- if (!Flags.extension10Bit() && format != ImageFormat.YUV_420_888) {
- Log.e(TAG, "Unsupported input format: " + format);
- return;
- }
mFormat = format;
initializePipeline();
}
@@ -251,7 +239,7 @@
private void initializePipeline() throws RemoteException {
if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) &&
(mYuvReader == null)) {
- if (Flags.extension10Bit() && mCaptureFormat == ImageFormat.YUV_420_888) {
+ if (mCaptureFormat == ImageFormat.YUV_420_888) {
// For the case when postview is JPEG and capture is YUV
mProcessor.onOutputSurface(mOutputSurface, mCaptureFormat);
} else {
@@ -274,7 +262,7 @@
private void initializePostviewPipeline() throws RemoteException {
if ((mFormat != -1) && (mPostviewOutputSurface != null) && (mPostviewResolution != null)
&& (mPostviewYuvReader == null)) {
- if (Flags.extension10Bit() && mPostviewFormat == ImageFormat.YUV_420_888) {
+ if (mPostviewFormat == ImageFormat.YUV_420_888) {
// For the case when postview is YUV and capture is JPEG
mProcessor.onPostviewOutputSurface(mPostviewOutputSurface);
} else {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index a4ae398..ce1609d 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -190,9 +190,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (int format : supportedCaptureOutputFormats.toArray()) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
@@ -401,7 +399,7 @@
if (surfaceInfo.mFormat == ImageFormat.JPEG) {
mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
mImageProcessor = mImageJpegProcessor;
- } else if (Flags.extension10Bit() && mClientPostviewSurface != null) {
+ } else if (mClientPostviewSurface != null) {
// Handles case when postview is JPEG and capture is YUV
CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
CameraExtensionUtils.querySurface(mClientPostviewSurface);
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 40f0477..f91d277 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -113,32 +113,13 @@
SurfaceInfo surfaceInfo = querySurface(outputConfig.getSurface());
- if (Flags.extension10Bit()) {
- Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
- if (supportedPostviewSizes.get(surfaceInfo.mFormat)
- .contains(postviewSize)) {
- return outputConfig.getSurface();
- } else {
- throw new IllegalArgumentException("Postview size not supported!");
- }
+ Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
+ if (supportedPostviewSizes.get(surfaceInfo.mFormat)
+ .contains(postviewSize)) {
+ return outputConfig.getSurface();
} else {
- if (surfaceInfo.mFormat == captureFormat) {
- if (supportedPostviewSizes.containsKey(captureFormat)) {
- Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
- if (supportedPostviewSizes.get(surfaceInfo.mFormat)
- .contains(postviewSize)) {
- return outputConfig.getSurface();
- } else {
- throw new IllegalArgumentException("Postview size not supported!");
- }
- }
- } else {
- throw new IllegalArgumentException("Postview format should be equivalent to "
- + " the capture format!");
- }
+ throw new IllegalArgumentException("Postview size not supported!");
}
-
- return null;
}
public static Surface getBurstCaptureSurface(
@@ -148,9 +129,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (OutputConfiguration config : outputConfigs) {
SurfaceInfo surfaceInfo = querySurface(config.getSurface());
for (int supportedFormat : supportedCaptureOutputFormats.toArray()) {
diff --git a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
index bf3f59f..73f4ff4 100644
--- a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
@@ -136,7 +136,6 @@
* or the color space implied by the dataSpace passed into an {@link ImageReader}'s
* constructor.</p>
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
mColorSpace = colorSpace.ordinal();
for (OutputConfiguration outputConfiguration : mOutputs) {
@@ -150,7 +149,6 @@
/**
* Clear the color space, such that the default color space will be used.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void clearColorSpace() {
mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
for (OutputConfiguration outputConfiguration : mOutputs) {
@@ -167,7 +165,6 @@
* @return the currently set color space, or null
* if not set
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
@SuppressLint("MethodNameUnits")
public @Nullable ColorSpace getColorSpace() {
if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 85e33a8..9612a53 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -21,6 +21,7 @@
import static android.view.Display.HdrCapabilities.HdrType;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -1232,6 +1233,20 @@
}
/**
+ * @param displayId The ID of the display
+ * @return The highest HDR/SDR ratio of the ratios defined in Display Device Config. If no
+ * HDR/SDR map is defined, this always returns 1.
+ */
+ @FlaggedApi(com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API)
+ public float getHighestHdrSdrRatio(int displayId) {
+ try {
+ return mDm.getHighestHdrSdrRatio(displayId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @see DisplayManager#getDozeBrightnessSensorValueToBrightness
*/
@RequiresPermission(Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index f3c21e9f..aa1539f6 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -247,6 +247,9 @@
@EnforcePermission("RESTRICT_DISPLAY_MODES")
void requestDisplayModes(in IBinder token, int displayId, in @nullable int[] modeIds);
+ // Get the highest defined HDR/SDR ratio for a display.
+ float getHighestHdrSdrRatio(int displayId);
+
// Get the mapping between the doze brightness sensor values and brightness values
@EnforcePermission("CONTROL_DISPLAY_BRIGHTNESS")
float[] getDozeBrightnessSensorValueToBrightness(int displayId);
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl
similarity index 63%
copy from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
copy to core/java/android/hardware/input/AidlKeyGestureEvent.aidl
index 48ec198..7cf8795 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright 2024 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.
@@ -14,12 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.scene.ui.composable.transitions
+package android.hardware.input;
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
+/** @hide */
+@JavaDerive(equals=true)
+parcelable AidlKeyGestureEvent {
+ int deviceId;
+ int[] keycodes;
+ int modifierState;
+ int gestureType;
+ int action;
+ int displayId;
+ int flags;
}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 2d96bba..102f56e 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -26,6 +26,7 @@
import android.hardware.input.IKeyboardBacklightListener;
import android.hardware.input.IKeyboardBacklightState;
import android.hardware.input.IKeyGestureEventListener;
+import android.hardware.input.IKeyGestureHandler;
import android.hardware.input.IStickyModifierStateListener;
import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.KeyboardLayoutSelectionResult;
@@ -250,4 +251,14 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.MANAGE_KEY_GESTURES)")
void unregisterKeyGestureEventListener(IKeyGestureEventListener listener);
+
+ @PermissionManuallyEnforced
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.MANAGE_KEY_GESTURES)")
+ void registerKeyGestureHandler(IKeyGestureHandler handler);
+
+ @PermissionManuallyEnforced
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.MANAGE_KEY_GESTURES)")
+ void unregisterKeyGestureHandler(IKeyGestureHandler handler);
}
diff --git a/core/java/android/hardware/input/IKeyGestureEventListener.aidl b/core/java/android/hardware/input/IKeyGestureEventListener.aidl
index 2c430f1..6b5f837 100644
--- a/core/java/android/hardware/input/IKeyGestureEventListener.aidl
+++ b/core/java/android/hardware/input/IKeyGestureEventListener.aidl
@@ -16,11 +16,13 @@
package android.hardware.input;
+import android.hardware.input.AidlKeyGestureEvent;
+
/** @hide */
oneway interface IKeyGestureEventListener {
/**
* Called when a key gesture event occurs.
*/
- void onKeyGestureEvent(int deviceId, in int[] keycodes, int modifierState, int shortcut);
+ void onKeyGestureEvent(in AidlKeyGestureEvent event);
}
diff --git a/core/java/android/hardware/input/IKeyGestureHandler.aidl b/core/java/android/hardware/input/IKeyGestureHandler.aidl
new file mode 100644
index 0000000..509b948
--- /dev/null
+++ b/core/java/android/hardware/input/IKeyGestureHandler.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2024 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.hardware.input;
+
+import android.hardware.input.AidlKeyGestureEvent;
+import android.os.IBinder;
+
+/** @hide */
+interface IKeyGestureHandler {
+
+ /**
+ * Called when a key gesture starts, ends, or is cancelled. If a handler returns {@code true},
+ * it means they intend to handle the full gesture and should handle all the events pertaining
+ * to that gesture.
+ */
+ boolean handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken);
+
+ /**
+ * Called to know if a particular gesture type is supported by the handler.
+ *
+ * TODO(b/358569822): Remove this call to reduce the binder calls to single call for
+ * handleKeyGesture. For this we need to remove dependency of multi-key gestures to identify if
+ * a key gesture is supported on first relevant key down.
+ * Also, for now we prioritize handlers in the system server process above external handlers to
+ * reduce IPC binder calls.
+ */
+ boolean isKeyGestureSupported(int gestureType);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 04cfcd8..22728f7 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1406,6 +1406,33 @@
}
/**
+ * Registers a key gesture event handler for {@link KeyGestureEvent} handling.
+ *
+ * @param handler the {@link KeyGestureEventHandler}
+ * @throws IllegalArgumentException if {@code handler} has already been registered previously.
+ * @throws NullPointerException if {@code handler} or {@code executor} is null.
+ * @hide
+ * @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler)
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ public void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler)
+ throws IllegalArgumentException {
+ mGlobal.registerKeyGestureEventHandler(handler);
+ }
+
+ /**
+ * Unregisters a previously added key gesture event handler.
+ *
+ * @param handler the {@link KeyGestureEventHandler}
+ * @hide
+ * @see #registerKeyGestureEventHandler(KeyGestureEventHandler)
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ public void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
+ mGlobal.unregisterKeyGestureEventHandler(handler);
+ }
+
+ /**
* A callback used to be notified about battery state changes for an input device. The
* {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the
* listener is successfully registered to provide the initial battery state of the device.
@@ -1522,4 +1549,35 @@
*/
void onKeyGestureEvent(@NonNull KeyGestureEvent event);
}
+
+ /**
+ * A callback used to notify about key gesture event start, complete and cancel. Unlike
+ * {@see KeyGestureEventListener} which is to listen to successfully handled key gestures, this
+ * interface allows system components to register handler for handling key gestures.
+ *
+ * @see #registerKeyGestureEventHandler(KeyGestureEventHandler)
+ * @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler)
+ *
+ * <p> NOTE: All callbacks will occur on system main and input threads, so the caller needs
+ * to move time-consuming operations to appropriate handler threads.
+ * @hide
+ */
+ public interface KeyGestureEventHandler {
+ /**
+ * Called when a key gesture event starts, is completed, or is cancelled. If a handler
+ * returns {@code true}, it implies that the handler intends to handle the key gesture and
+ * only this handler will receive the future events for this key gesture.
+ *
+ * @param event the gesture event
+ */
+ boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
+ @Nullable IBinder focusedToken);
+
+ /**
+ * Called to identify if a particular gesture is of interest to a handler.
+ *
+ * NOTE: If no active handler supports certain gestures, the gestures will not be captured.
+ */
+ boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType);
+ }
}
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 2a36238..5c11346 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -25,6 +25,7 @@
import android.hardware.SensorManager;
import android.hardware.input.InputManager.InputDeviceBatteryListener;
import android.hardware.input.InputManager.InputDeviceListener;
+import android.hardware.input.InputManager.KeyGestureEventHandler;
import android.hardware.input.InputManager.KeyGestureEventListener;
import android.hardware.input.InputManager.KeyboardBacklightListener;
import android.hardware.input.InputManager.OnTabletModeChangedListener;
@@ -119,6 +120,14 @@
@Nullable
private IKeyGestureEventListener mKeyGestureEventListener;
+ private final Object mKeyGestureEventHandlerLock = new Object();
+ @GuardedBy("mKeyGestureEventHandlerLock")
+ @Nullable
+ private ArrayList<KeyGestureEventHandler> mKeyGestureEventHandlers;
+ @GuardedBy("mKeyGestureEventHandlerLock")
+ @Nullable
+ private IKeyGestureHandler mKeyGestureHandler;
+
// InputDeviceSensorManager gets notified synchronously from the binder thread when input
// devices change, so it must be synchronized with the input device listeners.
@GuardedBy("mInputDeviceListeners")
@@ -1080,18 +1089,14 @@
}
private class LocalKeyGestureEventListener extends IKeyGestureEventListener.Stub {
-
@Override
- public void onKeyGestureEvent(int deviceId, int[] keycodes, int modifierState,
- int gestureType) {
+ public void onKeyGestureEvent(@NonNull AidlKeyGestureEvent ev) {
synchronized (mKeyGestureEventListenerLock) {
if (mKeyGestureEventListeners == null) return;
final int numListeners = mKeyGestureEventListeners.size();
+ final KeyGestureEvent event = new KeyGestureEvent(ev);
for (int i = 0; i < numListeners; i++) {
- mKeyGestureEventListeners.get(i)
- .onKeyGestureEvent(
- new KeyGestureEvent(deviceId, keycodes, modifierState,
- gestureType));
+ mKeyGestureEventListeners.get(i).onKeyGestureEvent(event);
}
}
}
@@ -1154,6 +1159,96 @@
}
}
+ private class LocalKeyGestureHandler extends IKeyGestureHandler.Stub {
+ @Override
+ public boolean handleKeyGesture(@NonNull AidlKeyGestureEvent ev, IBinder focusedToken) {
+ synchronized (mKeyGestureEventHandlerLock) {
+ if (mKeyGestureEventHandlers == null) {
+ return false;
+ }
+ final int numHandlers = mKeyGestureEventHandlers.size();
+ final KeyGestureEvent event = new KeyGestureEvent(ev);
+ for (int i = 0; i < numHandlers; i++) {
+ KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i);
+ if (handler.handleKeyGestureEvent(event, focusedToken)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
+ synchronized (mKeyGestureEventHandlerLock) {
+ if (mKeyGestureEventHandlers == null) {
+ return false;
+ }
+ final int numHandlers = mKeyGestureEventHandlers.size();
+ for (int i = 0; i < numHandlers; i++) {
+ KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i);
+ if (handler.isKeyGestureSupported(gestureType)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * @see InputManager#registerKeyGestureEventHandler(KeyGestureEventHandler)
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler)
+ throws IllegalArgumentException {
+ Objects.requireNonNull(handler, "handler should not be null");
+
+ synchronized (mKeyGestureEventHandlerLock) {
+ if (mKeyGestureHandler == null) {
+ mKeyGestureEventHandlers = new ArrayList<>();
+ mKeyGestureHandler = new LocalKeyGestureHandler();
+
+ try {
+ mIm.registerKeyGestureHandler(mKeyGestureHandler);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ final int numHandlers = mKeyGestureEventHandlers.size();
+ for (int i = 0; i < numHandlers; i++) {
+ if (mKeyGestureEventHandlers.get(i) == handler) {
+ throw new IllegalArgumentException("Handler has already been registered!");
+ }
+ }
+ mKeyGestureEventHandlers.add(handler);
+ }
+ }
+
+ /**
+ * @see InputManager#unregisterKeyGestureEventHandler(KeyGestureEventHandler)
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
+ Objects.requireNonNull(handler, "handler should not be null");
+
+ synchronized (mKeyGestureEventHandlerLock) {
+ if (mKeyGestureEventHandlers == null) {
+ return;
+ }
+ mKeyGestureEventHandlers.removeIf(existingHandler -> existingHandler == handler);
+ if (mKeyGestureEventHandlers.isEmpty()) {
+ try {
+ mIm.unregisterKeyGestureHandler(mKeyGestureHandler);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mKeyGestureEventHandlers = null;
+ mKeyGestureHandler = null;
+ }
+ }
+ }
+
/**
* TODO(b/330517633): Cleanup the unsupported API
*/
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 7a8dd33..c7ebc63 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -19,8 +19,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.view.Display;
+import android.view.KeyCharacterMap;
-import com.android.internal.util.DataClass;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AnnotationValidations;
import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
@@ -31,501 +34,511 @@
*
* @hide
*/
-@DataClass(genToString = true, genEqualsHashCode = true)
-public class KeyGestureEvent {
+public final class KeyGestureEvent {
- private final int mDeviceId;
@NonNull
- private final int[] mKeycodes;
- private final int mModifierState;
- @KeyGestureType
- private final int mKeyGestureType;
+ private AidlKeyGestureEvent mKeyGestureEvent;
+ public static final int KEY_GESTURE_TYPE_UNSPECIFIED = 0;
+ public static final int KEY_GESTURE_TYPE_HOME = 1;
+ public static final int KEY_GESTURE_TYPE_RECENT_APPS = 2;
+ public static final int KEY_GESTURE_TYPE_BACK = 3;
+ public static final int KEY_GESTURE_TYPE_APP_SWITCH = 4;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT = 5;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT = 6;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS = 7;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL = 8;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR = 9;
+ public static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT = 10;
+ public static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER = 11;
+ public static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP = 12;
+ public static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN = 13;
+ public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP = 14;
+ public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN = 15;
+ public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE = 16;
+ public static final int KEY_GESTURE_TYPE_VOLUME_UP = 17;
+ public static final int KEY_GESTURE_TYPE_VOLUME_DOWN = 18;
+ public static final int KEY_GESTURE_TYPE_VOLUME_MUTE = 19;
+ public static final int KEY_GESTURE_TYPE_ALL_APPS = 20;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH = 21;
+ public static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH = 22;
+ public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS = 23;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK = 24;
+ public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE = 25;
+ public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION = 26;
+ public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS = 27;
+ public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT = 28;
+ public static final int KEY_GESTURE_TYPE_LOCK_SCREEN = 29;
+ public static final int KEY_GESTURE_TYPE_OPEN_NOTES = 30;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_POWER = 31;
+ public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION = 32;
+ public static final int KEY_GESTURE_TYPE_SLEEP = 33;
+ public static final int KEY_GESTURE_TYPE_WAKEUP = 34;
+ public static final int KEY_GESTURE_TYPE_MEDIA_KEY = 35;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER = 36;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL = 37;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS = 38;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR = 39;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR = 40;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC = 41;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS = 42;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING = 43;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY = 44;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES = 45;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER = 46;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS = 47;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME = 48;
+ public static final int KEY_GESTURE_TYPE_DESKTOP_MODE = 49;
+ public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION = 50;
- public static final int KEY_GESTURE_TYPE_UNSPECIFIED =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
- public static final int KEY_GESTURE_TYPE_HOME =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME;
- public static final int KEY_GESTURE_TYPE_RECENT_APPS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS;
- public static final int KEY_GESTURE_TYPE_BACK =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK;
- public static final int KEY_GESTURE_TYPE_APP_SWITCH =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH;
- public static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT;
- public static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT;
- public static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS;
- public static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL;
- public static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR;
- public static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT;
- public static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER;
- public static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP;
- public static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN;
- public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP;
- public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN;
- public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE;
- public static final int KEY_GESTURE_TYPE_VOLUME_UP =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP;
- public static final int KEY_GESTURE_TYPE_VOLUME_DOWN =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN;
- public static final int KEY_GESTURE_TYPE_VOLUME_MUTE =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE;
- public static final int KEY_GESTURE_TYPE_ALL_APPS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS;
- public static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH;
- public static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH;
- public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS;
- public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK;
- public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE;
- public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION;
- public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS;
- public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT;
- public static final int KEY_GESTURE_TYPE_LOCK_SCREEN =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN;
- public static final int KEY_GESTURE_TYPE_OPEN_NOTES =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES;
- public static final int KEY_GESTURE_TYPE_TOGGLE_POWER =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER;
- public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION;
- public static final int KEY_GESTURE_TYPE_SLEEP =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP;
- public static final int KEY_GESTURE_TYPE_WAKEUP =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP;
- public static final int KEY_GESTURE_TYPE_MEDIA_KEY =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS;
- public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME;
- public static final int KEY_GESTURE_TYPE_DESKTOP_MODE =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
- public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION =
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
+ public static final int FLAG_CANCELLED = 1;
+ // NOTE: Valid KeyGestureEvent streams:
+ // - GESTURE_START -> GESTURE_CANCEL
+ // - GESTURE_START -> GESTURE_COMPLETE
+ // - GESTURE_COMPLETE
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/input/KeyGestureEvent.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
+ /** Key gesture started (e.g. Key down of the relevant key) */
+ public static final int ACTION_GESTURE_START = 1;
+ /** Key gesture completed (e.g. Key up of the relevant key) */
+ public static final int ACTION_GESTURE_COMPLETE = 2;
@IntDef(prefix = "KEY_GESTURE_TYPE_", value = {
- KEY_GESTURE_TYPE_UNSPECIFIED,
- KEY_GESTURE_TYPE_HOME,
- KEY_GESTURE_TYPE_RECENT_APPS,
- KEY_GESTURE_TYPE_BACK,
- KEY_GESTURE_TYPE_APP_SWITCH,
- KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
- KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT,
- KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
- KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
- KEY_GESTURE_TYPE_TOGGLE_TASKBAR,
- KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
- KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
- KEY_GESTURE_TYPE_BRIGHTNESS_UP,
- KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
- KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
- KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
- KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
- KEY_GESTURE_TYPE_VOLUME_UP,
- KEY_GESTURE_TYPE_VOLUME_DOWN,
- KEY_GESTURE_TYPE_VOLUME_MUTE,
- KEY_GESTURE_TYPE_ALL_APPS,
- KEY_GESTURE_TYPE_LAUNCH_SEARCH,
- KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
- KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
- KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
- KEY_GESTURE_TYPE_SYSTEM_MUTE,
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS,
- KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
- KEY_GESTURE_TYPE_LOCK_SCREEN,
- KEY_GESTURE_TYPE_OPEN_NOTES,
- KEY_GESTURE_TYPE_TOGGLE_POWER,
- KEY_GESTURE_TYPE_SYSTEM_NAVIGATION,
- KEY_GESTURE_TYPE_SLEEP,
- KEY_GESTURE_TYPE_WAKEUP,
- KEY_GESTURE_TYPE_MEDIA_KEY,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER,
- KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS,
- KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME,
- KEY_GESTURE_TYPE_DESKTOP_MODE,
- KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
+ KEY_GESTURE_TYPE_UNSPECIFIED,
+ KEY_GESTURE_TYPE_HOME,
+ KEY_GESTURE_TYPE_RECENT_APPS,
+ KEY_GESTURE_TYPE_BACK,
+ KEY_GESTURE_TYPE_APP_SWITCH,
+ KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
+ KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT,
+ KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
+ KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ KEY_GESTURE_TYPE_TOGGLE_TASKBAR,
+ KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
+ KEY_GESTURE_TYPE_BRIGHTNESS_UP,
+ KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
+ KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
+ KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
+ KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
+ KEY_GESTURE_TYPE_VOLUME_UP,
+ KEY_GESTURE_TYPE_VOLUME_DOWN,
+ KEY_GESTURE_TYPE_VOLUME_MUTE,
+ KEY_GESTURE_TYPE_ALL_APPS,
+ KEY_GESTURE_TYPE_LAUNCH_SEARCH,
+ KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ KEY_GESTURE_TYPE_SYSTEM_MUTE,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS,
+ KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
+ KEY_GESTURE_TYPE_LOCK_SCREEN,
+ KEY_GESTURE_TYPE_OPEN_NOTES,
+ KEY_GESTURE_TYPE_TOGGLE_POWER,
+ KEY_GESTURE_TYPE_SYSTEM_NAVIGATION,
+ KEY_GESTURE_TYPE_SLEEP,
+ KEY_GESTURE_TYPE_WAKEUP,
+ KEY_GESTURE_TYPE_MEDIA_KEY,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER,
+ KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS,
+ KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME,
+ KEY_GESTURE_TYPE_DESKTOP_MODE,
+ KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
})
@Retention(RetentionPolicy.SOURCE)
- @DataClass.Generated.Member
- public @interface KeyGestureType {}
+ public @interface KeyGestureType {
+ }
- @DataClass.Generated.Member
- public static String keyGestureTypeToString(@KeyGestureType int value) {
- switch (value) {
- case KEY_GESTURE_TYPE_UNSPECIFIED:
- return "KEY_GESTURE_TYPE_UNSPECIFIED";
- case KEY_GESTURE_TYPE_HOME:
- return "KEY_GESTURE_TYPE_HOME";
- case KEY_GESTURE_TYPE_RECENT_APPS:
- return "KEY_GESTURE_TYPE_RECENT_APPS";
- case KEY_GESTURE_TYPE_BACK:
- return "KEY_GESTURE_TYPE_BACK";
- case KEY_GESTURE_TYPE_APP_SWITCH:
- return "KEY_GESTURE_TYPE_APP_SWITCH";
- case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
- return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT";
- case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
- return "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT";
- case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
- return "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS";
- case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
- return "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL";
- case KEY_GESTURE_TYPE_TOGGLE_TASKBAR:
- return "KEY_GESTURE_TYPE_TOGGLE_TASKBAR";
- case KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
- return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT";
- case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
- return "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER";
- case KEY_GESTURE_TYPE_BRIGHTNESS_UP:
- return "KEY_GESTURE_TYPE_BRIGHTNESS_UP";
- case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
- return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN";
- case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
- return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP";
- case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
- return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN";
- case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
- return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE";
- case KEY_GESTURE_TYPE_VOLUME_UP:
- return "KEY_GESTURE_TYPE_VOLUME_UP";
- case KEY_GESTURE_TYPE_VOLUME_DOWN:
- return "KEY_GESTURE_TYPE_VOLUME_DOWN";
- case KEY_GESTURE_TYPE_VOLUME_MUTE:
- return "KEY_GESTURE_TYPE_VOLUME_MUTE";
- case KEY_GESTURE_TYPE_ALL_APPS:
- return "KEY_GESTURE_TYPE_ALL_APPS";
- case KEY_GESTURE_TYPE_LAUNCH_SEARCH:
- return "KEY_GESTURE_TYPE_LAUNCH_SEARCH";
- case KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
- return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH";
- case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
- return "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS";
- case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
- return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK";
- case KEY_GESTURE_TYPE_SYSTEM_MUTE:
- return "KEY_GESTURE_TYPE_SYSTEM_MUTE";
- case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
- return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION";
- case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
- return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS";
- case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
- return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT";
- case KEY_GESTURE_TYPE_LOCK_SCREEN:
- return "KEY_GESTURE_TYPE_LOCK_SCREEN";
- case KEY_GESTURE_TYPE_OPEN_NOTES:
- return "KEY_GESTURE_TYPE_OPEN_NOTES";
- case KEY_GESTURE_TYPE_TOGGLE_POWER:
- return "KEY_GESTURE_TYPE_TOGGLE_POWER";
- case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION:
- return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION";
- case KEY_GESTURE_TYPE_SLEEP:
- return "KEY_GESTURE_TYPE_SLEEP";
- case KEY_GESTURE_TYPE_WAKEUP:
- return "KEY_GESTURE_TYPE_WAKEUP";
- case KEY_GESTURE_TYPE_MEDIA_KEY:
- return "KEY_GESTURE_TYPE_MEDIA_KEY";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER";
- case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS:
- return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS";
- case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME:
- return "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME";
- case KEY_GESTURE_TYPE_DESKTOP_MODE:
- return "KEY_GESTURE_TYPE_DESKTOP_MODE";
- case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
- return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION";
- default: return Integer.toHexString(value);
+ public KeyGestureEvent(@NonNull AidlKeyGestureEvent keyGestureEvent) {
+ this.mKeyGestureEvent = keyGestureEvent;
+ }
+
+ /**
+ * Key gesture event builder used to create a KeyGestureEvent for tests in Java.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private int mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
+ private int[] mKeycodes = new int[0];
+ private int mModifierState = 0;
+ @KeyGestureType
+ private int mKeyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED;
+ private int mAction = KeyGestureEvent.ACTION_GESTURE_COMPLETE;
+ private int mDisplayId = Display.DEFAULT_DISPLAY;
+ private int mFlags = 0;
+
+ /**
+ * @see KeyGestureEvent#getDeviceId()
+ */
+ public Builder setDeviceId(int deviceId) {
+ mDeviceId = deviceId;
+ return this;
+ }
+
+ /**
+ * @see KeyGestureEvent#getKeycodes()
+ */
+ public Builder setKeycodes(@NonNull int[] keycodes) {
+ mKeycodes = keycodes;
+ return this;
+ }
+
+ /**
+ * @see KeyGestureEvent#getModifierState()
+ */
+ public Builder setModifierState(int modifierState) {
+ mModifierState = modifierState;
+ return this;
+ }
+
+ /**
+ * @see KeyGestureEvent#getKeyGestureType()
+ */
+ public Builder setKeyGestureType(@KeyGestureEvent.KeyGestureType int keyGestureType) {
+ mKeyGestureType = keyGestureType;
+ return this;
+ }
+
+ /**
+ * @see KeyGestureEvent#getAction()
+ */
+ public Builder setAction(int action) {
+ mAction = action;
+ return this;
+ }
+
+ /**
+ * @see KeyGestureEvent#getDisplayId()
+ */
+ public Builder setDisplayId(int displayId) {
+ mDisplayId = displayId;
+ return this;
+ }
+
+ /**
+ * @see KeyGestureEvent#getFlags()
+ */
+ public Builder setFlags(int flags) {
+ mFlags = flags;
+ return this;
+ }
+
+ /**
+ * Build {@link KeyGestureEvent}
+ */
+ public KeyGestureEvent build() {
+ AidlKeyGestureEvent event = new AidlKeyGestureEvent();
+ event.deviceId = mDeviceId;
+ event.keycodes = mKeycodes;
+ event.modifierState = mModifierState;
+ event.gestureType = mKeyGestureType;
+ event.action = mAction;
+ event.displayId = mDisplayId;
+ event.flags = mFlags;
+ return new KeyGestureEvent(event);
}
}
- @DataClass.Generated.Member
- public KeyGestureEvent(
- int deviceId,
- @NonNull int[] keycodes,
- int modifierState,
- @KeyGestureType int keyGestureType) {
- this.mDeviceId = deviceId;
- this.mKeycodes = keycodes;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mKeycodes);
- this.mModifierState = modifierState;
- this.mKeyGestureType = keyGestureType;
-
- if (!(mKeyGestureType == KEY_GESTURE_TYPE_UNSPECIFIED)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_HOME)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_RECENT_APPS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_BACK)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_APP_SWITCH)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_ASSISTANT)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_TASKBAR)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_TAKE_SCREENSHOT)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_BRIGHTNESS_UP)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_BRIGHTNESS_DOWN)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_UP)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_DOWN)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_MUTE)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_ALL_APPS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_SEARCH)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LANGUAGE_SWITCH)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_SYSTEM_MUTE)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LOCK_SCREEN)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_OPEN_NOTES)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_POWER)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_SYSTEM_NAVIGATION)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_SLEEP)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_WAKEUP)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_MEDIA_KEY)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_DESKTOP_MODE)
- && !(mKeyGestureType == KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION)) {
- throw new java.lang.IllegalArgumentException(
- "keyGestureType was " + mKeyGestureType + " but must be one of: "
- + "KEY_GESTURE_TYPE_UNSPECIFIED(" + KEY_GESTURE_TYPE_UNSPECIFIED + "), "
- + "KEY_GESTURE_TYPE_HOME(" + KEY_GESTURE_TYPE_HOME + "), "
- + "KEY_GESTURE_TYPE_RECENT_APPS(" + KEY_GESTURE_TYPE_RECENT_APPS + "), "
- + "KEY_GESTURE_TYPE_BACK(" + KEY_GESTURE_TYPE_BACK + "), "
- + "KEY_GESTURE_TYPE_APP_SWITCH(" + KEY_GESTURE_TYPE_APP_SWITCH + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT(" + KEY_GESTURE_TYPE_LAUNCH_ASSISTANT + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT(" + KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS(" + KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS + "), "
- + "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL(" + KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL + "), "
- + "KEY_GESTURE_TYPE_TOGGLE_TASKBAR(" + KEY_GESTURE_TYPE_TOGGLE_TASKBAR + "), "
- + "KEY_GESTURE_TYPE_TAKE_SCREENSHOT(" + KEY_GESTURE_TYPE_TAKE_SCREENSHOT + "), "
- + "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER(" + KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER + "), "
- + "KEY_GESTURE_TYPE_BRIGHTNESS_UP(" + KEY_GESTURE_TYPE_BRIGHTNESS_UP + "), "
- + "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN(" + KEY_GESTURE_TYPE_BRIGHTNESS_DOWN + "), "
- + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP + "), "
- + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN + "), "
- + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE + "), "
- + "KEY_GESTURE_TYPE_VOLUME_UP(" + KEY_GESTURE_TYPE_VOLUME_UP + "), "
- + "KEY_GESTURE_TYPE_VOLUME_DOWN(" + KEY_GESTURE_TYPE_VOLUME_DOWN + "), "
- + "KEY_GESTURE_TYPE_VOLUME_MUTE(" + KEY_GESTURE_TYPE_VOLUME_MUTE + "), "
- + "KEY_GESTURE_TYPE_ALL_APPS(" + KEY_GESTURE_TYPE_ALL_APPS + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_SEARCH(" + KEY_GESTURE_TYPE_LAUNCH_SEARCH + "), "
- + "KEY_GESTURE_TYPE_LANGUAGE_SWITCH(" + KEY_GESTURE_TYPE_LANGUAGE_SWITCH + "), "
- + "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS(" + KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS + "), "
- + "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK(" + KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK + "), "
- + "KEY_GESTURE_TYPE_SYSTEM_MUTE(" + KEY_GESTURE_TYPE_SYSTEM_MUTE + "), "
- + "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION(" + KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION + "), "
- + "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS(" + KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS + "), "
- + "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT(" + KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT + "), "
- + "KEY_GESTURE_TYPE_LOCK_SCREEN(" + KEY_GESTURE_TYPE_LOCK_SCREEN + "), "
- + "KEY_GESTURE_TYPE_OPEN_NOTES(" + KEY_GESTURE_TYPE_OPEN_NOTES + "), "
- + "KEY_GESTURE_TYPE_TOGGLE_POWER(" + KEY_GESTURE_TYPE_TOGGLE_POWER + "), "
- + "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION(" + KEY_GESTURE_TYPE_SYSTEM_NAVIGATION + "), "
- + "KEY_GESTURE_TYPE_SLEEP(" + KEY_GESTURE_TYPE_SLEEP + "), "
- + "KEY_GESTURE_TYPE_WAKEUP(" + KEY_GESTURE_TYPE_WAKEUP + "), "
- + "KEY_GESTURE_TYPE_MEDIA_KEY(" + KEY_GESTURE_TYPE_MEDIA_KEY + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS + "), "
- + "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME(" + KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME + "), "
- + "KEY_GESTURE_TYPE_DESKTOP_MODE(" + KEY_GESTURE_TYPE_DESKTOP_MODE + "), "
- + "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION(" + KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION + ")");
- }
-
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @DataClass.Generated.Member
public int getDeviceId() {
- return mDeviceId;
+ return mKeyGestureEvent.deviceId;
}
- @DataClass.Generated.Member
public @NonNull int[] getKeycodes() {
- return mKeycodes;
+ return mKeyGestureEvent.keycodes;
}
- @DataClass.Generated.Member
public int getModifierState() {
- return mModifierState;
+ return mKeyGestureEvent.modifierState;
}
- @DataClass.Generated.Member
public @KeyGestureType int getKeyGestureType() {
- return mKeyGestureType;
+ return mKeyGestureEvent.gestureType;
+ }
+
+ public int getAction() {
+ return mKeyGestureEvent.action;
+ }
+
+ public int getDisplayId() {
+ return mKeyGestureEvent.displayId;
+ }
+
+ public int getFlags() {
+ return mKeyGestureEvent.flags;
+ }
+
+ public boolean isCancelled() {
+ return (mKeyGestureEvent.flags & FLAG_CANCELLED) != 0;
}
@Override
- @DataClass.Generated.Member
public String toString() {
- // You can override field toString logic by defining methods like:
- // String fieldNameToString() { ... }
-
- return "KeyGestureEvent { " +
- "deviceId = " + mDeviceId + ", " +
- "keycodes = " + java.util.Arrays.toString(mKeycodes) + ", " +
- "modifierState = " + mModifierState + ", " +
- "keyGestureType = " + keyGestureTypeToString(mKeyGestureType) +
- " }";
+ return "KeyGestureEvent { "
+ + "deviceId = " + mKeyGestureEvent.deviceId + ", "
+ + "keycodes = " + java.util.Arrays.toString(mKeyGestureEvent.keycodes) + ", "
+ + "modifierState = " + mKeyGestureEvent.modifierState + ", "
+ + "keyGestureType = " + keyGestureTypeToString(mKeyGestureEvent.gestureType) + ", "
+ + "action = " + mKeyGestureEvent.action + ", "
+ + "displayId = " + mKeyGestureEvent.displayId + ", "
+ + "flags = " + mKeyGestureEvent.flags
+ + " }";
}
@Override
- @DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
- // You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(KeyGestureEvent other) { ... }
- // boolean fieldNameEquals(FieldType otherValue) { ... }
-
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- @SuppressWarnings("unchecked")
KeyGestureEvent that = (KeyGestureEvent) o;
- //noinspection PointlessBooleanExpression
- return true
- && mDeviceId == that.mDeviceId
- && java.util.Arrays.equals(mKeycodes, that.mKeycodes)
- && mModifierState == that.mModifierState
- && mKeyGestureType == that.mKeyGestureType;
+ return mKeyGestureEvent.deviceId == that.mKeyGestureEvent.deviceId
+ && java.util.Arrays.equals(mKeyGestureEvent.keycodes, that.mKeyGestureEvent.keycodes)
+ && mKeyGestureEvent.modifierState == that.mKeyGestureEvent.modifierState
+ && mKeyGestureEvent.gestureType == that.mKeyGestureEvent.gestureType
+ && mKeyGestureEvent.action == that.mKeyGestureEvent.action
+ && mKeyGestureEvent.displayId == that.mKeyGestureEvent.displayId
+ && mKeyGestureEvent.flags == that.mKeyGestureEvent.flags;
}
@Override
- @DataClass.Generated.Member
public int hashCode() {
- // You can override field hashCode logic by defining methods like:
- // int fieldNameHashCode() { ... }
-
int _hash = 1;
- _hash = 31 * _hash + mDeviceId;
- _hash = 31 * _hash + java.util.Arrays.hashCode(mKeycodes);
- _hash = 31 * _hash + mModifierState;
- _hash = 31 * _hash + mKeyGestureType;
+ _hash = 31 * _hash + mKeyGestureEvent.deviceId;
+ _hash = 31 * _hash + java.util.Arrays.hashCode(mKeyGestureEvent.keycodes);
+ _hash = 31 * _hash + mKeyGestureEvent.modifierState;
+ _hash = 31 * _hash + mKeyGestureEvent.gestureType;
+ _hash = 31 * _hash + mKeyGestureEvent.action;
+ _hash = 31 * _hash + mKeyGestureEvent.displayId;
+ _hash = 31 * _hash + mKeyGestureEvent.flags;
return _hash;
}
- @DataClass.Generated(
- time = 1723409092192L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/hardware/input/KeyGestureEvent.java",
- inputSignatures = "private final int mDeviceId\nprivate final @android.annotation.NonNull int[] mKeycodes\nprivate final int mModifierState\nprivate final @android.hardware.input.KeyGestureEvent.KeyGestureType int mKeyGestureType\npublic static final int KEY_GESTURE_TYPE_UNSPECIFIED\npublic static final int KEY_GESTURE_TYPE_HOME\npublic static final int KEY_GESTURE_TYPE_RECENT_APPS\npublic static final int KEY_GESTURE_TYPE_BACK\npublic static final int KEY_GESTURE_TYPE_APP_SWITCH\npublic static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT\npublic static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT\npublic static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS\npublic static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL\npublic static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR\npublic static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT\npublic static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER\npublic static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP\npublic static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN\npublic static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP\npublic static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN\npublic static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE\npublic static final int KEY_GESTURE_TYPE_VOLUME_UP\npublic static final int KEY_GESTURE_TYPE_VOLUME_DOWN\npublic static final int KEY_GESTURE_TYPE_VOLUME_MUTE\npublic static final int KEY_GESTURE_TYPE_ALL_APPS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH\npublic static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH\npublic static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS\npublic static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK\npublic static final int KEY_GESTURE_TYPE_SYSTEM_MUTE\npublic static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION\npublic static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS\npublic static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT\npublic static final int KEY_GESTURE_TYPE_LOCK_SCREEN\npublic static final int KEY_GESTURE_TYPE_OPEN_NOTES\npublic static final int KEY_GESTURE_TYPE_TOGGLE_POWER\npublic static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION\npublic static final int KEY_GESTURE_TYPE_SLEEP\npublic static final int KEY_GESTURE_TYPE_WAKEUP\npublic static final int KEY_GESTURE_TYPE_MEDIA_KEY\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME\npublic static final int KEY_GESTURE_TYPE_DESKTOP_MODE\npublic static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION\nclass KeyGestureEvent extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
- @Deprecated
- private void __metadata() {}
+ /**
+ * Convert KeyGestureEvent type to corresponding log event got KeyboardSystemsEvent
+ */
+ public static int keyGestureTypeToLogEvent(@KeyGestureType int value) {
+ switch (value) {
+ case KEY_GESTURE_TYPE_HOME:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME;
+ case KEY_GESTURE_TYPE_RECENT_APPS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS;
+ case KEY_GESTURE_TYPE_BACK:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK;
+ case KEY_GESTURE_TYPE_APP_SWITCH:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH;
+ case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT;
+ case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT;
+ case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS;
+ case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL;
+ case KEY_GESTURE_TYPE_TOGGLE_TASKBAR:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR;
+ case KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT;
+ case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER;
+ case KEY_GESTURE_TYPE_BRIGHTNESS_UP:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP;
+ case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN;
+ case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP;
+ case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN;
+ case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE;
+ case KEY_GESTURE_TYPE_VOLUME_UP:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP;
+ case KEY_GESTURE_TYPE_VOLUME_DOWN:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN;
+ case KEY_GESTURE_TYPE_VOLUME_MUTE:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE;
+ case KEY_GESTURE_TYPE_ALL_APPS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS;
+ case KEY_GESTURE_TYPE_LAUNCH_SEARCH:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH;
+ case KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH;
+ case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS;
+ case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK;
+ case KEY_GESTURE_TYPE_SYSTEM_MUTE:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE;
+ case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION;
+ case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS;
+ case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT;
+ case KEY_GESTURE_TYPE_LOCK_SCREEN:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN;
+ case KEY_GESTURE_TYPE_OPEN_NOTES:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES;
+ case KEY_GESTURE_TYPE_TOGGLE_POWER:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER;
+ case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION;
+ case KEY_GESTURE_TYPE_SLEEP:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP;
+ case KEY_GESTURE_TYPE_WAKEUP:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP;
+ case KEY_GESTURE_TYPE_MEDIA_KEY:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER;
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS;
+ case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME;
+ case KEY_GESTURE_TYPE_DESKTOP_MODE:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
+ case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
+ default:
+ return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
+ }
+ }
-
- //@formatter:on
- // End of generated code
-
+ private static String keyGestureTypeToString(@KeyGestureType int value) {
+ switch (value) {
+ case KEY_GESTURE_TYPE_UNSPECIFIED:
+ return "KEY_GESTURE_TYPE_UNSPECIFIED";
+ case KEY_GESTURE_TYPE_HOME:
+ return "KEY_GESTURE_TYPE_HOME";
+ case KEY_GESTURE_TYPE_RECENT_APPS:
+ return "KEY_GESTURE_TYPE_RECENT_APPS";
+ case KEY_GESTURE_TYPE_BACK:
+ return "KEY_GESTURE_TYPE_BACK";
+ case KEY_GESTURE_TYPE_APP_SWITCH:
+ return "KEY_GESTURE_TYPE_APP_SWITCH";
+ case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+ return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT";
+ case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
+ return "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT";
+ case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
+ return "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS";
+ case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
+ return "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL";
+ case KEY_GESTURE_TYPE_TOGGLE_TASKBAR:
+ return "KEY_GESTURE_TYPE_TOGGLE_TASKBAR";
+ case KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
+ return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT";
+ case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
+ return "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER";
+ case KEY_GESTURE_TYPE_BRIGHTNESS_UP:
+ return "KEY_GESTURE_TYPE_BRIGHTNESS_UP";
+ case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
+ return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN";
+ case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+ return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP";
+ case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+ return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN";
+ case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+ return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE";
+ case KEY_GESTURE_TYPE_VOLUME_UP:
+ return "KEY_GESTURE_TYPE_VOLUME_UP";
+ case KEY_GESTURE_TYPE_VOLUME_DOWN:
+ return "KEY_GESTURE_TYPE_VOLUME_DOWN";
+ case KEY_GESTURE_TYPE_VOLUME_MUTE:
+ return "KEY_GESTURE_TYPE_VOLUME_MUTE";
+ case KEY_GESTURE_TYPE_ALL_APPS:
+ return "KEY_GESTURE_TYPE_ALL_APPS";
+ case KEY_GESTURE_TYPE_LAUNCH_SEARCH:
+ return "KEY_GESTURE_TYPE_LAUNCH_SEARCH";
+ case KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
+ return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH";
+ case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
+ return "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS";
+ case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+ return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK";
+ case KEY_GESTURE_TYPE_SYSTEM_MUTE:
+ return "KEY_GESTURE_TYPE_SYSTEM_MUTE";
+ case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
+ return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION";
+ case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
+ return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS";
+ case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
+ return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT";
+ case KEY_GESTURE_TYPE_LOCK_SCREEN:
+ return "KEY_GESTURE_TYPE_LOCK_SCREEN";
+ case KEY_GESTURE_TYPE_OPEN_NOTES:
+ return "KEY_GESTURE_TYPE_OPEN_NOTES";
+ case KEY_GESTURE_TYPE_TOGGLE_POWER:
+ return "KEY_GESTURE_TYPE_TOGGLE_POWER";
+ case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION:
+ return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION";
+ case KEY_GESTURE_TYPE_SLEEP:
+ return "KEY_GESTURE_TYPE_SLEEP";
+ case KEY_GESTURE_TYPE_WAKEUP:
+ return "KEY_GESTURE_TYPE_WAKEUP";
+ case KEY_GESTURE_TYPE_MEDIA_KEY:
+ return "KEY_GESTURE_TYPE_MEDIA_KEY";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER";
+ case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS:
+ return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS";
+ case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME:
+ return "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME";
+ case KEY_GESTURE_TYPE_DESKTOP_MODE:
+ return "KEY_GESTURE_TYPE_DESKTOP_MODE";
+ case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
+ return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION";
+ default:
+ return Integer.toHexString(value);
+ }
+ }
}
diff --git a/core/java/android/hardware/input/VirtualInputDeviceConfig.java b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
index a87980c..e8ef8cd 100644
--- a/core/java/android/hardware/input/VirtualInputDeviceConfig.java
+++ b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
@@ -57,7 +57,7 @@
mVendorId = builder.mVendorId;
mProductId = builder.mProductId;
mAssociatedDisplayId = builder.mAssociatedDisplayId;
- mInputDeviceName = Objects.requireNonNull(builder.mInputDeviceName);
+ mInputDeviceName = Objects.requireNonNull(builder.mInputDeviceName, "Missing device name");
if (mAssociatedDisplayId == Display.INVALID_DISPLAY) {
throw new IllegalArgumentException(
@@ -77,7 +77,7 @@
mVendorId = in.readInt();
mProductId = in.readInt();
mAssociatedDisplayId = in.readInt();
- mInputDeviceName = Objects.requireNonNull(in.readString8());
+ mInputDeviceName = Objects.requireNonNull(in.readString8(), "Missing device name");
}
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c4d12d4..996a288 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2066,9 +2066,11 @@
public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
// Event for reporting change of some device states, triggered by a specific UID
public static final int EVENT_STATE_CHANGE = 0x0015;
+ // Event for reporting change of screen states.
+ public static final int EVENT_DISPLAY_STATE_CHANGED = 0x0016;
// Number of event types.
- public static final int EVENT_COUNT = 0x0016;
+ public static final int EVENT_COUNT = 0x0017;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -3079,13 +3081,14 @@
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
"active", "pkginst", "pkgunin", "alarm", "stats", "pkginactive", "pkgactive",
- "tmpwhitelist", "screenwake", "wakeupap", "longwake", "state"
+ "tmpwhitelist", "screenwake", "wakeupap", "longwake", "state",
+ "display_state_changed"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
"Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw",
- "Esw", "Ewa", "Elw", "Eec", "Esc"
+ "Esw", "Ewa", "Elw", "Eec", "Esc", "Eds"
};
@FunctionalInterface
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index f7b4173..93a8ed9 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -134,7 +134,6 @@
* The maximum value of supported bugreport mode.
* @hide
*/
- @FlaggedApi(android.os.Flags.FLAG_BUGREPORT_MODE_MAX_VALUE)
@TestApi
public static final int BUGREPORT_MODE_MAX_VALUE = BUGREPORT_MODE_ONBOARDING;
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 360b2ac..73cdd56 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -33,7 +33,7 @@
* if creation is supported but fails.
*/
IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds,
- in long durationNanos, in SessionTag tag, out @nullable SessionConfig config);
+ in long durationNanos, in SessionTag tag, out SessionConfig config);
/**
* Get preferred rate limit in nanoseconds.
@@ -48,6 +48,6 @@
*
* Throws IllegalStateException if FMQ channel creation fails.
*/
- ChannelConfig getSessionChannel(in IBinder token);
+ @nullable ChannelConfig getSessionChannel(in IBinder token);
oneway void closeSessionChannel();
}
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index bf44d65..0776cf4 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
@@ -551,7 +552,7 @@
}
/**
- * An interface suitable for a lambda expression instead of a QueryHandler.
+ * An interface suitable for a lambda expression instead of a QueryHandler applying remote call.
* @hide
*/
public interface RemoteCall<Query, Result> {
@@ -559,6 +560,14 @@
}
/**
+ * An interface suitable for a lambda expression instead of a QueryHandler bypassing the cache.
+ * @hide
+ */
+ public interface BypassCall<Query> {
+ Boolean apply(Query query);
+ }
+
+ /**
* This is a query handler that is created with a lambda expression that is invoked
* every time the handler is called. The handler is specifically meant for services
* hosted by system_server; the handler automatically rethrows RemoteException as a
@@ -580,11 +589,54 @@
}
}
+
/**
* Create a cache using a config and a lambda expression.
+ * @param config The configuration for the cache.
+ * @param remoteCall The lambda expression that will be invoked to fetch the data.
* @hide
*/
- public IpcDataCache(@NonNull Config config, @NonNull RemoteCall<Query, Result> computer) {
- this(config, new SystemServerCallHandler<>(computer));
+ public IpcDataCache(@NonNull Config config, @NonNull RemoteCall<Query, Result> remoteCall) {
+ this(config, android.multiuser.Flags.cachingDevelopmentImprovements() ?
+ new QueryHandler<Query, Result>() {
+ @Override
+ public Result apply(Query query) {
+ try {
+ return remoteCall.apply(query);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ } : new SystemServerCallHandler<>(remoteCall));
+ }
+
+
+ /**
+ * Create a cache using a config and a lambda expression.
+ * @param config The configuration for the cache.
+ * @param remoteCall The lambda expression that will be invoked to fetch the data.
+ * @param bypass The lambda expression that will be invoked to determine if the cache should be
+ * bypassed.
+ * @hide
+ */
+ @FlaggedApi(android.multiuser.Flags.FLAG_CACHING_DEVELOPMENT_IMPROVEMENTS)
+ public IpcDataCache(@NonNull Config config,
+ @NonNull RemoteCall<Query, Result> remoteCall,
+ @NonNull BypassCall<Query> bypass) {
+ this(config, new QueryHandler<Query, Result>() {
+ @Override
+ public Result apply(Query query) {
+ try {
+ return remoteCall.apply(query);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean shouldBypassCache(Query query) {
+ return bypass.apply(query);
+ }
+ });
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 3b2041b..346ee7c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -589,6 +589,12 @@
**/
public static final int THREAD_GROUP_RESTRICTED = 7;
+ /**
+ * Thread group for foreground apps in multi-window mode
+ * @hide
+ **/
+ public static final int THREAD_GROUP_FOREGROUND_WINDOW = 8;
+
/** @hide */
public static final int SIGNAL_DEFAULT = 0;
public static final int SIGNAL_QUIT = 3;
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 58ab5b6..cfbf528 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -138,11 +138,14 @@
Log.w(TAG, "Failed to vibrate; no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason=" + reason);
try {
mService.vibrate(uid, mContext.getDeviceId(), opPkg, effect, attributes, reason,
mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -152,11 +155,14 @@
Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedback, reason=" + reason);
try {
mService.performHapticFeedback(mUid, mContext.getDeviceId(), mPackageName, constant,
reason, flags, privFlags);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -168,11 +174,15 @@
+ " no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR,
+ "performHapticFeedbackForInputDevice, reason=" + reason);
try {
mService.performHapticFeedbackForInputDevice(mUid, mContext.getDeviceId(), mPackageName,
constant, inputDeviceId, inputSource, reason, flags, privFlags);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback for input device.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f1ec0e4e..a4a7a98 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1539,10 +1539,19 @@
* Specifies that the managed profile is not allowed to have unified lock screen challenge with
* the primary user.
*
- * <p><strong>Note:</strong> Setting this restriction alone doesn't automatically set a
- * separate challenge. Profile owner can ask the user to set a new password using
- * {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} and verify it using
- * {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}.
+ * <p>To ensure that there is a separate work profile password, IT admins
+ * have to:
+ * <ol>
+ * <li>Enforce {@link UserManager#DISALLOW_UNIFIED_PASSWORD}</li>
+ * <li>Verify that {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}
+ * returns true. This indicates that there is now a separate work
+ * profile password configured and the set up is completed.</li>
+ * <li>In case {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}
+ * returns false, invoke {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD}
+ * intent and then verify again
+ * {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}.</li>
+ * </ol>
+ * </p>
*
* <p>Can be set by profile owners. It only has effect on managed profiles when set by managed
* profile owner. Has no effect on non-managed profiles or users.
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index f026997..39bd15c 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -52,14 +52,6 @@
}
flag {
- name: "bugreport_mode_max_value"
- is_exported: true
- namespace: "telephony"
- description: "Introduce a constant as maximum value of bugreport mode."
- bug: "305067125"
-}
-
-flag {
name: "adpf_prefer_power_efficiency"
is_exported: true
namespace: "game"
@@ -115,14 +107,6 @@
}
flag {
- name: "adpf_fmq_eager_send"
- namespace: "game"
- description: "Guards the use of an eager-sending optimization in FMQ for low-latency messages"
- is_fixed_read_only: true
- bug: "315894228"
-}
-
-flag {
name: "adpf_hwui_gpu"
namespace: "game"
description: "Guards use of the FMQ channel for ADPF"
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index bc6c570..e6e5a27 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -30,17 +30,13 @@
import android.annotation.Nullable;
import android.content.res.Resources;
-import android.os.SystemProperties;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.os.Vibrator.VibrationIntensity;
import android.util.IndentingPrintWriter;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.function.Function;
/**
* List of device-specific internal vibration configuration loaded from platform config.xml.
@@ -54,37 +50,6 @@
public class VibrationConfig {
/**
- * The default gain to be applied between vibration scale levels.
- *
- * <p>Scale levels are defined as the difference between the user vibration intensity setting
- * and the device default config for each usage. The intensity values are defined as one of
- * Vibrator.VIBRATION_INTENSITY_*.
- *
- * <p>A user setting HIGH set on a device with default value LOW will cause the vibration
- * intensity to be scaled up 2 levels, i.e. scale with a factor of gain^2. A system with 3
- * intensities LOW, MEDIUM and HIGH has the following 5 scale levels:
- *
- * <ol>
- * <li>VERY_HIGH: user(HIGH) - device(LOW)
- * <li>HIGH: user(HIGH) - device(MEDIUM) / user(MEDIUM) - device(LOW)
- * <li>NONE: user == device
- * <li>LOW: user(MEDIUM) - device(HIGH) / user(LOW) - device(MEDIUM)
- * <li>VERY_LOW: user(LOW) - device(HIGH)
- * </ol>
- *
- * <p>A device will only ever apply 3 out of these 5 levels based on the default intensity
- * config set for each usage (e.g. config_default[Alarm|Ring|Notification]VibrationIntensity).
- *
- * <p>This value must be greater than 1. The {@link #DEFAULT_SCALE_LEVEL_GAIN} will be used if
- * this property is undefined or invalid.
- *
- * @hide
- */
- @VisibleForTesting
- static final String SCALE_LEVEL_GAIN_SYSTEM_PROPERTY =
- "vendor.vibrator.scale.level.gain";
-
- /**
* Hardcoded default scale level gain to be applied between each scale level to define their
* scale factor value.
*
@@ -104,7 +69,7 @@
private final int mRampDownDurationMs;
private final int mRequestVibrationParamsTimeoutMs;
private final int[] mRequestVibrationParamsForUsages;
- private final float mDefaultVibrationScaleLevelGain;
+
private final boolean mIgnoreVibrationsOnWirelessCharger;
@VibrationIntensity
@@ -124,18 +89,8 @@
/** @hide */
public VibrationConfig(@Nullable Resources resources) {
- this(resources, SystemProperties::get);
- }
-
- /** @hide */
- @VisibleForTesting
- public VibrationConfig(@Nullable Resources resources,
- Function<String, String> systemPropertiesGetter) {
- mDefaultVibrationAmplitude = loadInteger(resources,
- com.android.internal.R.integer.config_defaultVibrationAmplitude,
- DEFAULT_AMPLITUDE);
- mDefaultVibrationScaleLevelGain = loadFloat(systemPropertiesGetter,
- SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, DEFAULT_SCALE_LEVEL_GAIN);
+ mDefaultVibrationAmplitude = resources.getInteger(
+ com.android.internal.R.integer.config_defaultVibrationAmplitude);
mHapticChannelMaxVibrationAmplitude = loadFloat(resources,
com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude);
mRampDownDurationMs = loadInteger(resources,
@@ -180,15 +135,6 @@
return res != null ? res.getFloat(resId) : 0f;
}
- private static float loadFloat(Function<String, String> systemPropertiesGetter,
- String propertyKey, float defaultValue) {
- try {
- return Float.parseFloat(systemPropertiesGetter.apply(propertyKey));
- } catch (Exception e) {
- return defaultValue;
- }
- }
-
private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) {
return res != null ? res.getInteger(resId) : defaultValue;
}
@@ -230,10 +176,8 @@
* for each level.
*/
public float getDefaultVibrationScaleLevelGain() {
- if (mDefaultVibrationScaleLevelGain <= 1) {
- return DEFAULT_SCALE_LEVEL_GAIN;
- }
- return mDefaultVibrationScaleLevelGain;
+ // TODO(b/356407380): add device config for this
+ return DEFAULT_SCALE_LEVEL_GAIN;
}
/**
@@ -326,7 +270,6 @@
return "VibrationConfig{"
+ "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger
+ ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude
- + ", mDefaultVibrationScaleLevelGain=" + mDefaultVibrationScaleLevelGain
+ ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude
+ ", mRampStepDurationMs=" + mRampStepDurationMs
+ ", mRampDownDurationMs=" + mRampDownDurationMs
@@ -353,7 +296,6 @@
pw.increaseIndent();
pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger);
pw.println("defaultVibrationAmplitude = " + mDefaultVibrationAmplitude);
- pw.println("defaultVibrationScaleLevelGain = " + mDefaultVibrationScaleLevelGain);
pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude);
pw.println("rampStepDurationMs = " + mRampStepDurationMs);
pw.println("rampDownDurationMs = " + mRampDownDurationMs);
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 6c486db..b0791e3 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -249,3 +249,19 @@
description: "This flag is used to enabled the Wallet Role s icon fetching from manifest property"
bug: "349942654"
}
+
+flag {
+ name: "replace_body_sensors_permission_enabled"
+ is_exported: true
+ namespace: "android_health_services"
+ description: "This flag is used to enable replacing permission BODY_SENSORS(and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE(and READ_HEALTH_DATA_IN_BACKGROUND)"
+ bug: "364638912"
+}
+
+flag {
+ name: "appop_access_tracking_logging_enabled"
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enables logging of the AppOp access tracking"
+ bug: "365584286"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0a05f70..e32625e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -17818,6 +17818,12 @@
public static final String FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT =
"force_non_debuggable_final_build_for_compat";
+ /**
+ * Flag to enable the use of ApplicationInfo for getting not-launched status.
+ *
+ * @hide
+ */
+ public static final String ENABLE_USE_APP_INFO_NOT_LAUNCHED = "use_app_info_not_launched";
/**
* Current version of signed configuration applied.
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index f6f0eff..a86c961 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -99,3 +99,10 @@
description: "Causes TrustManagerService to listen for credential attempts and ignore reports from upstream"
bug: "323086607"
}
+
+flag {
+ name: "clear_strong_auth_on_add_primary_credential"
+ namespace: "biometrics"
+ description: "Clear StrongAuth on add credential"
+ bug: "320817991"
+}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 3d8d933..752f174 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -2553,7 +2553,7 @@
if (!Flags.modesUi()) {
return manualRule != null;
}
- return manualRule != null && manualRule.isAutomaticActive();
+ return manualRule != null && manualRule.isActive();
}
public static class ZenRule implements Parcelable {
@@ -2932,8 +2932,7 @@
}
}
- // TODO: b/363193376 - Rename to isActive()
- public boolean isAutomaticActive() {
+ public boolean isActive() {
if (Flags.modesApi() && Flags.modesUi()) {
if (!enabled || getPkg() == null) {
return false;
@@ -3173,7 +3172,7 @@
// DND turned on by an automatic rule
for (ZenRule automaticRule : config.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
if (isValidEventConditionId(automaticRule.conditionId)
|| isValidScheduleConditionId(automaticRule.conditionId)) {
// set text if automatic rule end time is the latest active rule end time
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java
index 05c2a9c..60a7d6b 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -495,8 +495,8 @@
// Even if added or removed, there may be a change in whether or not it was active.
// This only applies to automatic rules.
- boolean fromActive = from != null ? from.isAutomaticActive() : false;
- boolean toActive = to != null ? to.isAutomaticActive() : false;
+ boolean fromActive = from != null ? from.isActive() : false;
+ boolean toActive = to != null ? to.isActive() : false;
if (fromActive != toActive) {
mActiveDiff = new FieldDiff<>(fromActive, toActive);
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 82c52a6..f8c97eb 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -20,6 +20,8 @@
import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API;
+import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API;
+
import android.Manifest;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -1499,6 +1501,15 @@
}
/**
+ * @return The highest possible HDR/SDR ratio. If {@link #isHdrSdrRatioAvailable()} returns
+ * false, this method returns 1.
+ */
+ @FlaggedApi(FLAG_HIGHEST_HDR_SDR_RATIO_API)
+ public float getHighestHdrSdrRatio() {
+ return mGlobal.getHighestHdrSdrRatio(mDisplayId);
+ }
+
+ /**
* Sets the default {@link Display.Mode} to use for the display. The display mode includes
* preference for resolution and refresh rate.
* If the mode specified is not supported by the display, then no mode change occurs.
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index e9c85684..658aa29 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -21,4 +21,5 @@
name: "enable_touch_scroll_feedback"
description: "Enables touchscreen haptic scroll feedback"
bug: "331830899"
+ is_fixed_read_only: true
}
diff --git a/core/java/android/webkit/WebViewUpdateManager.java b/core/java/android/webkit/WebViewUpdateManager.java
index 0eb71001..b9a5e4ae 100644
--- a/core/java/android/webkit/WebViewUpdateManager.java
+++ b/core/java/android/webkit/WebViewUpdateManager.java
@@ -43,22 +43,29 @@
/**
* Get the singleton instance of the manager.
*
- * This exists for the benefit of callsites without a {@link Context}; prefer
+ * <p>This exists for the benefit of callsites without a {@link Context}; prefer
* {@link Context#getSystemService(Class)} otherwise.
*
- * This can only be used on devices with {@link PackageManager#FEATURE_WEBVIEW}.
+ * <p>This must only be called on devices with {@link PackageManager#FEATURE_WEBVIEW},
+ * and will WTF or throw {@link UnsupportedOperationException} otherwise.
*/
@SuppressLint("ManagerLookup") // service opts in to getSystemServiceWithNoContext()
@RequiresFeature(PackageManager.FEATURE_WEBVIEW)
- public static @Nullable WebViewUpdateManager getInstance() {
- return (WebViewUpdateManager) SystemServiceRegistry.getSystemServiceWithNoContext(
- Context.WEBVIEW_UPDATE_SERVICE);
+ public static @NonNull WebViewUpdateManager getInstance() {
+ WebViewUpdateManager manager =
+ (WebViewUpdateManager) SystemServiceRegistry.getSystemServiceWithNoContext(
+ Context.WEBVIEW_UPDATE_SERVICE);
+ if (manager == null) {
+ throw new UnsupportedOperationException("WebView not supported by device");
+ } else {
+ return manager;
+ }
}
/**
* Block until system-level WebView preparations are complete.
*
- * This also makes the current WebView provider package visible to the caller.
+ * <p>This also makes the current WebView provider package visible to the caller.
*
* @return the status of WebView preparation and the current provider package.
*/
@@ -86,7 +93,7 @@
/**
* Get the complete list of supported WebView providers for this device.
*
- * This includes all configured providers, regardless of whether they are currently available
+ * <p>This includes all configured providers, regardless of whether they are currently available
* or valid.
*/
@SuppressLint({"ParcelableList", "ArrayReturn"})
@@ -101,13 +108,15 @@
/**
* Get the list of currently-valid WebView providers for this device.
*
- * This only includes providers that are currently present on the device and meet the validity
- * criteria (signature, version, etc), but does not check if the provider is installed and
- * enabled for all users.
+ * <p>This only includes providers that are currently present on the device and meet the
+ * validity criteria (signature, version, etc), but does not check if the provider is installed
+ * and enabled for all users.
+ *
+ * <p>Note that this will be filtered by the caller's package visibility; callers should
+ * have QUERY_ALL_PACKAGES permission to ensure that the list is complete.
*/
@SuppressLint({"ParcelableList", "ArrayReturn"})
- @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS,
- android.Manifest.permission.QUERY_ALL_PACKAGES})
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public @NonNull WebViewProviderInfo[] getValidWebViewPackages() {
try {
return mService.getValidWebViewPackages();
@@ -132,7 +141,7 @@
/**
* Ask the system to switch to a specific WebView implementation if possible.
*
- * This choice will be stored persistently.
+ * <p>This choice will be stored persistently.
*
* @param newProvider the package name to use.
* @return the package name which is now in use, which may not be the
@@ -162,7 +171,7 @@
/**
* Get the WebView provider which will be used if no explicit choice has been made.
*
- * The default provider is not guaranteed to be a valid/usable WebView implementation.
+ * <p>The default provider is not guaranteed to be a valid/usable WebView implementation.
*
* @return the default WebView provider.
*/
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
index 01af182..644d917 100644
--- a/core/java/android/webkit/WebViewUpdateService.java
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.RemoteException;
@@ -54,7 +55,11 @@
/**
* Fetch all packages that could potentially implement WebView and are currently valid.
+ *
+ * <p>Note that this will be filtered by the caller's package visibility; callers should
+ * have QUERY_ALL_PACKAGES permission to ensure that the list is complete.
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public static WebViewProviderInfo[] getValidWebViewPackages() {
if (Flags.updateServiceIpcWrapper()) {
if (WebViewFactory.isWebViewSupported()) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 89ea852..e1154ca 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -83,6 +83,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.os.Trace;
import android.os.UserHandle;
import android.system.Os;
import android.text.TextUtils;
@@ -7003,6 +7004,18 @@
private View inflateView(Context context, RemoteViews rv, @Nullable ViewGroup parent,
@StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
+ try {
+ Trace.beginSection(rv.hasDrawInstructions()
+ ? "RemoteViews#inflateViewWithDrawInstructions"
+ : "RemoteViews#inflateView");
+ return inflateViewInternal(context, rv, parent, applyThemeResId, colorResources);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private View inflateViewInternal(Context context, RemoteViews rv, @Nullable ViewGroup parent,
+ @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
// RemoteViews may be built by an application installed in another
// user. So build a context that loads resources from that user but
// still returns the current users userId so settings like data / time formats
@@ -7169,10 +7182,17 @@
if (mRV.mActions != null) {
int count = mRV.mActions.size();
mActions = new Action[count];
- for (int i = 0; i < count && !isCancelled(); i++) {
- // TODO: check if isCancelled in nested views.
- mActions[i] = mRV.mActions.get(i)
- .initActionAsync(mTree, mParent, mApplyParams);
+ try {
+ Trace.beginSection(hasDrawInstructions()
+ ? "RemoteViews#initActionAsyncWithDrawInstructions"
+ : "RemoteViews#initActionAsync");
+ for (int i = 0; i < count && !isCancelled(); i++) {
+ // TODO: check if isCancelled in nested views.
+ mActions[i] = mRV.mActions.get(i)
+ .initActionAsync(mTree, mParent, mApplyParams);
+ }
+ } finally {
+ Trace.endSection();
}
} else {
mActions = null;
@@ -7194,13 +7214,19 @@
try {
if (mActions != null) {
-
ActionApplyParams applyParams = mApplyParams.clone();
if (applyParams.handler == null) {
applyParams.handler = DEFAULT_INTERACTION_HANDLER;
}
- for (Action a : mActions) {
- a.apply(viewTree.mRoot, mParent, applyParams);
+ try {
+ Trace.beginSection(hasDrawInstructions()
+ ? "RemoteViews#applyActionsAsyncWithDrawInstructions"
+ : "RemoteViews#applyActionsAsync");
+ for (Action a : mActions) {
+ a.apply(viewTree.mRoot, mParent, applyParams);
+ }
+ } finally {
+ Trace.endSection();
}
}
// If the parent of the view is has is a root, resolve the recycling.
@@ -7387,8 +7413,15 @@
}
if (mActions != null) {
final int count = mActions.size();
- for (int i = 0; i < count; i++) {
- mActions.get(i).apply(v, parent, params);
+ try {
+ Trace.beginSection(hasDrawInstructions()
+ ? "RemoteViews#applyActionsWithDrawInstructions"
+ : "RemoteViews#applyActions");
+ for (int i = 0; i < count; i++) {
+ mActions.get(i).apply(v, parent, params);
+ }
+ } finally {
+ Trace.endSection();
}
}
}
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index bccee92..0632a37 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -76,7 +76,7 @@
* @param callback The callback to be registered. If the callback instance has been already
* registered, the existing instance (no matter its priority) will be
* unregistered and registered again.
- * @throws {@link IllegalArgumentException} if the priority is negative.
+ * @throws IllegalArgumentException if the priority is negative.
*/
@SuppressLint({"ExecutorRegistration"})
void registerOnBackInvokedCallback(
diff --git a/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java b/core/java/android/window/flags/DesktopModeFlags.java
similarity index 82%
rename from services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java
rename to core/java/android/window/flags/DesktopModeFlags.java
index d33313e..5c53d66 100644
--- a/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java
+++ b/core/java/android/window/flags/DesktopModeFlags.java
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.utils;
-
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET;
+package android.window.flags;
import android.annotation.Nullable;
import android.content.Context;
@@ -28,18 +26,18 @@
import java.util.function.Supplier;
/**
- * Util to check desktop mode flags state.
+ * Checks desktop mode flag state.
*
- * This utility is used to allow developer option toggles to override flags related to desktop
- * windowing.
+ * <p>This enum provides a centralized way to control the behavior of flags related to desktop
+ * windowing features which are aiming for developer preview before their release. It allows
+ * developer option to override the default behavior of these flags.
*
- * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag
- * value and the developer option override state (if applicable).
+ * <p>NOTE: Flags should only be added to this enum when they have received Product and UX
+ * alignment that the feature is ready for developer preview, otherwise just do a flag check.
*
- * This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} which
- * is to be used in WM core.
+ * @hide
*/
-public enum DesktopModeFlagsUtil {
+public enum DesktopModeFlags {
// All desktop mode related flags to be overridden by developer option toggle will be added here
DESKTOP_WINDOWING_MODE(
Flags::enableDesktopWindowingMode, /* shouldOverrideByDevOption= */ true),
@@ -55,7 +53,7 @@
// be refreshed only on reboots as overridden state is expected to take effect on reboots.
private static ToggleOverride sCachedToggleOverride;
- DesktopModeFlagsUtil(Supplier<Boolean> flagFunction, boolean shouldOverrideByDevOption) {
+ DesktopModeFlags(Supplier<Boolean> flagFunction, boolean shouldOverrideByDevOption) {
this.mFlagFunction = flagFunction;
this.mShouldOverrideByDevOption = shouldOverrideByDevOption;
}
@@ -101,13 +99,13 @@
int settingValue = Settings.Global.getInt(
context.getContentResolver(),
Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
- OVERRIDE_UNSET.getSetting()
+ ToggleOverride.OVERRIDE_UNSET.getSetting()
);
- return ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET);
+ return ToggleOverride.fromSetting(settingValue, ToggleOverride.OVERRIDE_UNSET);
}
/** Override state of desktop mode developer option toggle. */
- enum ToggleOverride {
+ private enum ToggleOverride {
OVERRIDE_UNSET,
OVERRIDE_OFF,
OVERRIDE_ON;
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 8e81951..0f401d3 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -145,6 +145,13 @@
}
flag {
+ name: "enable_resizing_metrics"
+ namespace: "lse_desktop_experience"
+ description: "Whether to enable log collection for task resizing in desktop windowing mode"
+ bug: "341319100"
+}
+
+flag {
name: "enable_caption_compat_inset_force_consumption"
namespace: "lse_desktop_experience"
description: "Enables force-consumption of caption bar insets for immersive apps in freeform"
@@ -215,6 +222,13 @@
}
flag {
+ name: "enable_desktop_windowing_exit_transitions"
+ namespace: "lse_desktop_experience"
+ description: "Enables exit desktop windowing transition & motion polish changes"
+ bug: "353650462"
+}
+
+flag {
name: "enable_compat_ui_visibility_status"
namespace: "lse_desktop_experience"
description: "Enables the tracking of the status for compat ui elements."
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index a786fc2..69b91fd 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -144,6 +144,13 @@
}
flag {
+ name: "universal_resizable_by_default"
+ namespace: "windowing_frontend"
+ description: "The orientation, aspect ratio, resizability of activity will follow system behavior by default"
+ bug: "357141415"
+}
+
+flag {
name: "respect_non_top_visible_fixed_orientation"
namespace: "windowing_frontend"
description: "If top activity is not opaque, respect the fixed orientation of activity behind it"
@@ -181,6 +188,17 @@
}
flag {
+ name: "update_dims_when_window_shown"
+ namespace: "windowing_frontend"
+ description: "Check if we need to update dim layers when a new window draws the first frame"
+ bug: "327332488"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "release_snapshot_aggressively"
namespace: "windowing_frontend"
description: "Actively release task snapshot memory"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 8077a55..13648de 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -115,3 +115,10 @@
bug: "289875940"
is_fixed_read_only: true
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "touch_pass_through_opt_in"
+ description: "Requires apps to opt-in to overlay pass through touches and provide APIs to opt-in"
+ bug: "358129114"
+}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index ebcae27..a5e166b 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -144,9 +144,9 @@
@EnforcePermission("UPDATE_DEVICE_STATS")
void noteGpsSignalQuality(int signalLevel);
@EnforcePermission("UPDATE_DEVICE_STATS")
- void noteScreenState(int state);
+ void noteScreenState(int displayId, int state, int reason);
@EnforcePermission("UPDATE_DEVICE_STATS")
- void noteScreenBrightness(int brightness);
+ void noteScreenBrightness(int displayId, int brightness);
@EnforcePermission("UPDATE_DEVICE_STATS")
void noteUserActivity(int uid, int event);
@EnforcePermission("UPDATE_DEVICE_STATS")
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index b873175..39aadfb 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -18,6 +18,7 @@
import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import android.aconfig.DeviceProtos;
import android.aconfig.nano.Aconfig;
import android.aconfig.nano.Aconfig.parsed_flag;
import android.aconfig.nano.Aconfig.parsed_flags;
@@ -40,7 +41,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.List;
+import java.util.Arrays;
import java.util.Map;
/**
@@ -54,12 +55,6 @@
public class AconfigFlags {
private static final String LOG_TAG = "AconfigFlags";
- private static final List<String> sTextProtoFilesOnDevice = List.of(
- "/system/etc/aconfig_flags.pb",
- "/system_ext/etc/aconfig_flags.pb",
- "/product/etc/aconfig_flags.pb",
- "/vendor/etc/aconfig_flags.pb");
-
public enum Permission {
READ_WRITE,
READ_ONLY
@@ -73,7 +68,10 @@
Slog.v(LOG_TAG, "Feature disabled, skipped all loading");
return;
}
- for (String fileName : sTextProtoFilesOnDevice) {
+ final var defaultFlagProtoFiles =
+ (Process.myUid() == Process.SYSTEM_UID) ? DeviceProtos.parsedFlagsProtoPaths()
+ : Arrays.asList(DeviceProtos.PATHS);
+ for (String fileName : defaultFlagProtoFiles) {
try (var inputStream = new FileInputStream(fileName)) {
loadAconfigDefaultValues(inputStream.readAllBytes());
} catch (IOException e) {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index e5ac0e1..49191ee 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -404,6 +404,11 @@
return;
}
break;
+ case SP_FOREGROUND_WINDOW:
+ if (!CgroupGetAttributePath("HighCapacityWICPUs", &filename)) {
+ return;
+ }
+ break;
case SP_TOP_APP:
if (!CgroupGetAttributePath("MaxCapacityCPUs", &filename)) {
return;
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index c1022a5..664d54d 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -43,3 +43,10 @@
name: "bugreport_artifacts",
srcs: ["config/test-sysconfig.xml"],
}
+
+test_module_config {
+ name: "BugreportManagerTestCases_android_server_os",
+ base: "BugreportManagerTestCases",
+ test_suites: ["general-tests"],
+ exclude_annotations: ["androidx.test.filters.LargeTest"],
+}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 5111d2d..d98836f 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -303,6 +303,7 @@
name: "FrameworksCoreTests_Presubmit",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -313,6 +314,7 @@
name: "FrameworksCoreTests_inputmethod",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -327,6 +329,7 @@
name: "FrameworksCoreTests_context",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -337,6 +340,7 @@
name: "FrameworksCoreTests_keyguard_manager",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -347,6 +351,7 @@
name: "FrameworksCoreTests_property_invalidated_cache",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -357,6 +362,7 @@
name: "FrameworksCoreTests_android_content",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -371,6 +377,7 @@
name: "FrameworksCoreTests_sqlite",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -381,6 +388,7 @@
name: "FrameworksCoreTests_android_net",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -392,6 +400,7 @@
name: "FrameworksCoreTests_battery_stats",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -403,6 +412,7 @@
name: "FrameworksCoreTests_environment",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -413,6 +423,7 @@
name: "FrameworksCoreTests_util_data_charset",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -426,6 +437,7 @@
name: "FrameworksCoreTests_xml",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -439,6 +451,7 @@
name: "FrameworksCoreTests_util_apk",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -449,6 +462,7 @@
name: "FrameworksCoreTests_textclassifier",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -460,6 +474,7 @@
name: "FrameworksCoreTests_internal_app",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -474,6 +489,7 @@
name: "FrameworksCoreTests_internal_content",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -484,6 +500,7 @@
name: "FrameworksCoreTests_internal_infra",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -494,6 +511,7 @@
name: "FrameworksCoreTests_internal_jank",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -504,6 +522,7 @@
name: "FrameworksCoreTests_internal_os_binder",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -515,6 +534,7 @@
name: "FrameworksCoreTests_internal_os_kernel",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -531,6 +551,7 @@
name: "FrameworksCoreTests_server_power",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -541,6 +562,7 @@
name: "FrameworksCoreTests_internal_security",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -552,6 +574,7 @@
name: "FrameworksCoreTests_internal_util_latency_tracker",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -562,6 +585,7 @@
name: "FrameworksCoreTests_content_capture_options",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -572,6 +596,7 @@
name: "FrameworksCoreTests_android_content_integrity",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -582,6 +607,7 @@
name: "FrameworksCoreTests_android_content_pm_PreSubmit",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -593,6 +619,7 @@
name: "FrameworksCoreTests_android_content_pm_PostSubmit",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -604,6 +631,7 @@
name: "FrameworksCoreTests_android_content_res",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -620,6 +648,7 @@
name: "FrameworksCoreTests_android_content_res_PostSubmit",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -631,6 +660,7 @@
name: "FrameworksCoreTests_android_service",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -650,6 +680,7 @@
name: "FrameworksCoreTests_android_view_contentcapture",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -660,6 +691,7 @@
name: "FrameworksCoreTests_android_view_contentprotection",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -670,6 +702,7 @@
name: "FrameworksCoreTests_com_android_internal_content_Presubmit",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -681,6 +714,7 @@
name: "FrameworksCoreTests_drawable",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -691,6 +725,7 @@
name: "FrameworksCoreTests_accessibility",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -705,6 +740,7 @@
name: "FrameworksCoreTests_usage",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -715,6 +751,7 @@
name: "FrameworksCoreTests_fastdata",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -725,6 +762,7 @@
name: "FrameworksCoreTests_hardware_input",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -735,6 +773,7 @@
name: "FrameworksCoreTests_view_verified",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -745,9 +784,34 @@
}
test_module_config {
+ name: "FrameworksCoreTests_android_net_Presubmit",
+ base: "FrameworksCoreTests",
+ test_suites: [
+ "automotive-tests",
+ "device-platinum-tests",
+ "device-tests",
+ ],
+ include_filters: ["android.net"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
+
+test_module_config {
+ name: "FrameworksCoreTests_content_pm_Postsubmit",
+ base: "FrameworksCoreTests",
+ test_suites: [
+ "automotive-tests",
+ "device-platinum-tests",
+ "device-tests",
+ ],
+ include_filters: ["android.content.pm."],
+ include_annotations: ["android.platform.test.annotations.Postsubmit"],
+}
+
+test_module_config {
name: "FrameworksCoreTests_jank",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
@@ -762,6 +826,7 @@
name: "FrameworksCoreTests_Platinum",
base: "FrameworksCoreTests",
test_suites: [
+ "automotive-tests",
"device-tests",
"device-platinum-tests",
],
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index ef6ff05..0837b45 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -215,6 +215,25 @@
}
@Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void testGetShortCriticalText_noneSet() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .build();
+
+ assertSame(n.getShortCriticalText(), null);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void testGetShortCriticalText_isSet() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setShortCriticalText("short critical text here")
+ .build();
+
+ assertSame(n.getShortCriticalText(), "short critical text here");
+ }
+
+ @Test
public void largeIconMultipleReferences_keptAfterParcelling() {
Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
index b03fd64..64f77b3 100644
--- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java
+++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
@@ -18,7 +18,9 @@
import static org.junit.Assert.assertEquals;
+import android.multiuser.Flags;
import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
@@ -151,8 +153,6 @@
tester.verify(9);
}
- // This test is disabled pending an sepolicy change that allows any app to set the
- // test property.
@Test
public void testRemoteCall() {
@@ -193,6 +193,44 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHING_DEVELOPMENT_IMPROVEMENTS)
+ public void testRemoteCallBypass() {
+
+ // A stand-in for the binder. The test verifies that calls are passed through to
+ // this class properly.
+ ServerProxy tester = new ServerProxy();
+
+ // Create a cache that uses simple arithmetic to computer its values.
+ IpcDataCache.Config config = new IpcDataCache.Config(4, MODULE, API, "testCache3");
+ IpcDataCache<Integer, Boolean> testCache =
+ new IpcDataCache<>(config, (x) -> tester.query(x), (x) -> x % 9 == 0);
+
+ IpcDataCache.setTestMode(true);
+ testCache.testPropertyName();
+
+ tester.verify(0);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(1);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(2);
+ testCache.invalidateCache();
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(3);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(4);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(4);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(4);
+ assertEquals(tester.value(9), testCache.query(9));
+ tester.verify(5);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(5);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(5);
+ }
+
+ @Test
public void testDisableCache() {
// A stand-in for the binder. The test verifies that calls are passed through to
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
similarity index 77%
rename from services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java
rename to core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
index 46b8e3a..32345e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java
+++ b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.server.wm.utils;
+package android.window.flags;
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.DESKTOP_WINDOWING_MODE;
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_OFF;
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_ON;
+import static android.window.flags.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
+
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS;
import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION;
@@ -26,16 +25,16 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.ContentResolver;
+import android.content.Context;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-
-import com.android.server.wm.WindowTestRunner;
-import com.android.server.wm.WindowTestsBase;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Rule;
@@ -45,21 +44,28 @@
import java.lang.reflect.Field;
/**
- * Test class for [DesktopModeFlagsUtil]
+ * Test class for {@link DesktopModeFlags}
*
* Build/Install/Run:
- * atest WmTests:DesktopModeFlagsUtilTest
+ * atest FrameworksCoreTests:DesktopModeFlagsTest
*/
@SmallTest
@Presubmit
-@RunWith(WindowTestRunner.class)
-public class DesktopModeFlagsUtilTest extends WindowTestsBase {
+@RunWith(AndroidJUnit4.class)
+public class DesktopModeFlagsTest {
@Rule
public SetFlagsRule setFlagsRule = new SetFlagsRule();
+ private Context mContext;
+
+ private static final int OVERRIDE_OFF_SETTING = 0;
+ private static final int OVERRIDE_ON_SETTING = 1;
+ private static final int OVERRIDE_UNSET_SETTING = -1;
+
@Before
public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
resetCache();
}
@@ -67,7 +73,7 @@
@DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// In absence of dev options, follow flag
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
}
@@ -76,7 +82,7 @@
@Test
@DisableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
public void isEnabled_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
}
@@ -84,7 +90,7 @@
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
public void isEnabled_overrideUnset_featureFlagOn_returnsTrue() {
- setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+ setOverride(OVERRIDE_UNSET_SETTING);
// For overridableFlag, for unset overrides, follow flag
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
@@ -94,7 +100,7 @@
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_overrideUnset_featureFlagOff_returnsFalse() {
- setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+ setOverride(OVERRIDE_UNSET_SETTING);
// For overridableFlag, for unset overrides, follow flag
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
@@ -141,7 +147,7 @@
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
public void isEnabled_overrideOff_featureFlagOn_returnsFalse() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// For overridableFlag, follow override if they exist
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
@@ -151,7 +157,7 @@
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_overrideOn_featureFlagOff_returnsTrue() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// For overridableFlag, follow override if they exist
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
@@ -160,12 +166,12 @@
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
public void isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// For overridableFlag, follow override if they exist
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// Keep overrides constant through the process
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
@@ -175,12 +181,12 @@
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// For overridableFlag, follow override if they exist
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// Keep overrides constant through the process
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
@@ -190,19 +196,19 @@
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS})
public void isEnabled_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() {
- setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+ setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
@DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void isEnabled_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
- setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+ setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
}
@Test
@@ -212,20 +218,20 @@
FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
})
public void isEnabled_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
@DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void isEnabled_dwFlagOn_overrideOn_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
}
@Test
@@ -235,20 +241,20 @@
FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
})
public void isEnabled_dwFlagOn_overrideOff_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
@DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
public void isEnabled_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
}
@Test
@@ -258,10 +264,10 @@
})
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() {
- setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+ setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
}
@Test
@@ -271,10 +277,10 @@
FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
})
public void isEnabled_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() {
- setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+ setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
}
@Test
@@ -284,10 +290,10 @@
})
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
}
@Test
@@ -297,10 +303,10 @@
FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
})
public void isEnabled_dwFlagOff_overrideOn_featureFlagOff_returnFalse() {
- setOverride(OVERRIDE_ON.getSetting());
+ setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
}
@Test
@@ -310,10 +316,10 @@
})
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
public void isEnabled_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
}
@Test
@@ -323,10 +329,10 @@
FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
})
public void isEnabled_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_OFF.getSetting());
+ setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
}
private void setOverride(Integer setting) {
@@ -341,7 +347,7 @@
}
private void resetCache() throws Exception {
- Field cachedToggleOverride = DesktopModeFlagsUtil.class.getDeclaredField(
+ Field cachedToggleOverride = DesktopModeFlags.class.getDeclaredField(
"sCachedToggleOverride");
cachedToggleOverride.setAccessible(true);
cachedToggleOverride.set(null, null);
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
index e0f1012..74c7b4c 100644
--- a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
@@ -32,8 +32,8 @@
"truth",
],
libs: [
- "android.test.runner",
- "android.test.base",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
],
test_suites: [
"device-tests",
diff --git a/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java b/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java
deleted file mode 100644
index a2ff9d7..0000000
--- a/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.vibrator;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-
-import com.android.internal.R;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class VibrationConfigTest {
-
- @Rule
- public MockitoRule rule = MockitoJUnit.rule();
-
- @Mock
- private Resources mResourcesMock;
-
- private final Map<String, String> mSystemProperties = new HashMap<>();
-
- @Test
- public void getDefaultVibrationAmplitude_returnsConfiguredAmplitude() {
- when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(1);
- assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(1);
-
- when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(123);
- assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(123);
-
- when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(255);
- assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
- }
-
- @Test
- public void getDefaultVibrationAmplitude_invalidValue_returnsMaxAmplitude() {
- when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(-1);
- assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
-
- when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(0);
- assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
-
- when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(500);
- assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
- }
-
- @Test
- public void getDefaultVibrationScaleLevelGain_returnsConfiguredGain() {
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "1.2");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.2f);
-
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "2");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(2f);
- }
-
- @Test
- public void getDefaultVibrationScaleLevelGain_invalidValue_returnsFixedScaleGain() {
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "invalid");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "-1");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "0.5");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
- mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "1.0");
- assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
- }
-
- private VibrationConfig createConfig() {
- return new VibrationConfig(mResourcesMock, mSystemProperties::get);
- }
-}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
index bc46b70..bd430c0 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp
+++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
@@ -62,3 +62,10 @@
enabled: false,
},
}
+
+test_module_config {
+ name: "WMJetpackUnitTests_Presubmit",
+ base: "WMJetpackUnitTests",
+ test_suites: ["device-tests"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index a79bc97..94809f2 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -187,6 +187,9 @@
"shared/**/desktopmode/*.java",
"shared/**/desktopmode/*.kt",
],
+ static_libs: [
+ "com.android.window.flags.window-aconfig-java",
+ ],
}
android_library {
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index c6044a4..394093c6 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,6 @@
xutan@google.com
+pbdr@google.com
+pragyabajoria@google.com
# Give submodule owners in shell resource approval
per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com, pragyabajoria@google.com, uysalorhan@google.com, gsennton@google.com, mattsziklay@google.com, mdehaini@google.com
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
index 1871203..b6db6d9 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
@@ -72,8 +72,8 @@
"platform-screenshot-diff-core",
],
libs: [
- "android.test.base",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
jni_libs: [
"libdexmakerjvmtiagent",
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_manage_windows.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_manage_windows.xml
new file mode 100644
index 0000000..7d912a2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_manage_windows.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/black" android:pathData="M160,880Q127,880 103.5,856.5Q80,833 80,800L80,440Q80,407 103.5,383.5Q127,360 160,360L240,360L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,520Q880,553 856.5,576.5Q833,600 800,600L720,600L720,800Q720,833 696.5,856.5Q673,880 640,880L160,880ZM160,800L640,800Q640,800 640,800Q640,800 640,800L640,520L160,520L160,800Q160,800 160,800Q160,800 160,800ZM720,520L800,520Q800,520 800,520Q800,520 800,520L800,240L320,240L320,360L640,360Q673,360 696.5,383.5Q720,407 720,440L720,520Z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index eea3de8..64f71c7 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -147,6 +147,14 @@
android:drawableStart="@drawable/desktop_mode_ic_handle_menu_new_window"
android:drawableTint="?androidprv:attr/materialColorOnSurface"
style="@style/DesktopModeHandleMenuActionButton" />
+
+ <Button
+ android:id="@+id/manage_windows_button"
+ android:contentDescription="@string/manage_windows_text"
+ android:text="@string/manage_windows_text"
+ android:drawableStart="@drawable/desktop_mode_ic_handle_menu_manage_windows"
+ android:drawableTint="?androidprv:attr/materialColorOnSurface"
+ style="@style/DesktopModeHandleMenuActionButton" />
</LinearLayout>
<LinearLayout
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 755e0d5..c76c470 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -504,9 +504,9 @@
<!-- The width of the handle menu in desktop mode. -->
<dimen name="desktop_mode_handle_menu_width">216dp</dimen>
- <!-- The maximum height of the handle menu in desktop mode. Four pills (52dp each) plus 2dp
- spacing between them plus 4dp top padding. -->
- <dimen name="desktop_mode_handle_menu_height">270dp</dimen>
+ <!-- The maximum height of the handle menu in desktop mode. Three pills at 52dp each,
+ additional actions pill 156dp, plus 2dp spacing between them plus 4dp top padding. -->
+ <dimen name="desktop_mode_handle_menu_height">322dp</dimen>
<!-- The elevation set on the handle menu pills. -->
<dimen name="desktop_mode_handle_menu_pill_elevation">1dp</dimen>
@@ -520,6 +520,9 @@
<!-- The maximum height of the handle menu's "New Window" button in desktop mode. -->
<dimen name="desktop_mode_handle_menu_new_window_height">52dp</dimen>
+ <!-- The maximum height of the handle menu's "Manage Windows" button in desktop mode. -->
+ <dimen name="desktop_mode_handle_menu_manage_windows_height">52dp</dimen>
+
<!-- The maximum height of the handle menu's "Screenshot" button in desktop mode. -->
<dimen name="desktop_mode_handle_menu_screenshot_height">52dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index a353db7..a6da421 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -294,6 +294,8 @@
<string name="open_in_browser_text">Open in browser</string>
<!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] -->
<string name="new_window_text">New Window</string>
+ <!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] -->
+ <string name="manage_windows_text">Manage Windows</string>
<!-- Accessibility text for the handle menu close button [CHAR LIMIT=NONE] -->
<string name="close_text">Close</string>
<!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] -->
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
new file mode 100644
index 0000000..79becb0
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.shared.desktopmode
+import android.annotation.ColorInt
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.RoundRectShape
+import android.util.TypedValue
+import android.view.MotionEvent.ACTION_OUTSIDE
+import android.view.SurfaceView
+import android.view.ViewGroup.MarginLayoutParams
+import android.widget.LinearLayout
+import android.window.TaskSnapshot
+
+/**
+ * View for the All Windows menu option, used by both Desktop Windowing and Taskbar.
+ * The menu displays icons of all open instances of an app. Clicking the icon should launch
+ * the instance, which will be performed by the child class.
+ */
+abstract class ManageWindowsViewContainer(
+ val context: Context,
+ @ColorInt private val menuBackgroundColor: Int
+) {
+ lateinit var menuView: ManageWindowsView
+
+ /** Creates the base menu view and fills it with icon views. */
+ fun show(snapshotList: List<Pair<Int, TaskSnapshot>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)): ManageWindowsView {
+ menuView = ManageWindowsView(context, menuBackgroundColor).apply {
+ this.onOutsideClickListener = onOutsideClickListener
+ this.onIconClickListener = onIconClickListener
+ this.generateIconViews(snapshotList)
+ }
+ addToContainer(menuView)
+ return menuView
+ }
+
+ /** Adds the menu view to the container responsible for displaying it. */
+ abstract fun addToContainer(menuView: ManageWindowsView)
+
+ /** Dispose of the menu, perform needed cleanup. */
+ abstract fun close()
+
+ companion object {
+ const val MANAGE_WINDOWS_MINIMUM_INSTANCES = 2
+ }
+
+ class ManageWindowsView(
+ private val context: Context,
+ menuBackgroundColor: Int
+ ) {
+ val rootView: LinearLayout = LinearLayout(context)
+ var menuHeight = 0
+ var menuWidth = 0
+ var onIconClickListener: ((Int) -> Unit)? = null
+ var onOutsideClickListener: (() -> Unit)? = null
+
+ init {
+ rootView.orientation = LinearLayout.VERTICAL
+ val menuBackground = ShapeDrawable()
+ val menuRadius = getDimensionPixelSize(MENU_RADIUS_DP)
+ menuBackground.shape = RoundRectShape(
+ FloatArray(8) { menuRadius },
+ null,
+ null
+ )
+ menuBackground.paint.color = menuBackgroundColor
+ rootView.background = menuBackground
+ rootView.elevation = getDimensionPixelSize(MENU_ELEVATION_DP)
+ rootView.setOnTouchListener { _, event ->
+ if (event.actionMasked == ACTION_OUTSIDE) {
+ onOutsideClickListener?.invoke()
+ }
+ return@setOnTouchListener true
+ }
+ }
+
+ private fun getDimensionPixelSize(sizeDp: Float): Float {
+ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ sizeDp, context.resources.displayMetrics)
+ }
+
+ fun generateIconViews(
+ snapshotList: List<Pair<Int, TaskSnapshot>>
+ ) {
+ menuWidth = 0
+ menuHeight = 0
+ rootView.removeAllViews()
+ val instanceIconHeight = getDimensionPixelSize(ICON_HEIGHT_DP)
+ val instanceIconWidth = getDimensionPixelSize(ICON_WIDTH_DP)
+ val iconRadius = getDimensionPixelSize(ICON_RADIUS_DP)
+ val iconMargin = getDimensionPixelSize(ICON_MARGIN_DP)
+ var rowLayout: LinearLayout? = null
+ // Add each icon to the menu, adding a new row when needed.
+ for ((iconCount, taskInfoSnapshotPair) in snapshotList.withIndex()) {
+ val taskId = taskInfoSnapshotPair.first
+ val snapshot = taskInfoSnapshotPair.second
+ // Once a row is filled, make a new row and increase the menu height.
+ if (iconCount % MENU_MAX_ICONS_PER_ROW == 0) {
+ rowLayout = LinearLayout(context)
+ rowLayout.orientation = LinearLayout.HORIZONTAL
+ rootView.addView(rowLayout)
+ menuHeight += (instanceIconHeight + iconMargin).toInt()
+ }
+ val snapshotBitmap = Bitmap.wrapHardwareBuffer(
+ snapshot.hardwareBuffer,
+ snapshot.colorSpace
+ )
+ val scaledSnapshotBitmap = snapshotBitmap?.let {
+ Bitmap.createScaledBitmap(
+ it, instanceIconWidth.toInt(), instanceIconHeight.toInt(), true /* filter */
+ )
+ }
+ val appSnapshotButton = SurfaceView(context)
+ appSnapshotButton.cornerRadius = iconRadius
+ appSnapshotButton.setZOrderOnTop(true)
+ appSnapshotButton.setOnClickListener {
+ onIconClickListener?.invoke(taskId)
+ }
+ val lp = MarginLayoutParams(
+ instanceIconWidth.toInt(), instanceIconHeight.toInt()
+ )
+ lp.apply {
+ marginStart = iconMargin.toInt()
+ topMargin = iconMargin.toInt()
+ }
+ appSnapshotButton.layoutParams = lp
+ // If we haven't already reached one full row, increment width.
+ if (iconCount < MENU_MAX_ICONS_PER_ROW) {
+ menuWidth += (instanceIconWidth + iconMargin).toInt()
+ }
+ rowLayout?.addView(appSnapshotButton)
+ appSnapshotButton.requestLayout()
+ rowLayout?.post {
+ appSnapshotButton.holder.surface
+ .attachAndQueueBufferWithColorSpace(
+ scaledSnapshotBitmap?.hardwareBuffer,
+ scaledSnapshotBitmap?.colorSpace
+ )
+ }
+ }
+ // Add margin again for the right/bottom of the menu.
+ menuWidth += iconMargin.toInt()
+ menuHeight += iconMargin.toInt()
+ }
+
+ companion object {
+ private const val MENU_RADIUS_DP = 26f
+ private const val ICON_WIDTH_DP = 204f
+ private const val ICON_HEIGHT_DP = 127.5f
+ private const val ICON_RADIUS_DP = 16f
+ private const val ICON_MARGIN_DP = 16f
+ private const val MENU_ELEVATION_DP = 1f
+ private const val MENU_MAX_ICONS_PER_ROW = 3
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java
index 133242d..a27caf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java
@@ -57,6 +57,12 @@
Rect startingBounds = pipBoundsState.getBounds().isEmpty()
? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
: pipBoundsState.getBounds();
+ // If IME is not showing and restore bounds (pre-IME bounds) is not empty, we should set PiP
+ // bounds to the restore bounds.
+ if (!pipBoundsState.isImeShowing() && !pipBoundsState.getRestoreBounds().isEmpty()) {
+ startingBounds.set(pipBoundsState.getRestoreBounds());
+ pipBoundsState.clearRestoreBounds();
+ }
Rect insets = new Rect();
pipBoundsAlgorithm.getInsetBounds(insets);
if (pipBoundsState.isImeShowing()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index 140d776..c487f75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -86,6 +86,7 @@
@NonNull private final Rect mExpandedBounds = new Rect();
@NonNull private final Rect mNormalMovementBounds = new Rect();
@NonNull private final Rect mExpandedMovementBounds = new Rect();
+ @NonNull private final Rect mRestoreBounds = new Rect();
@NonNull private final PipDisplayLayoutState mPipDisplayLayoutState;
private final Point mMaxSize = new Point();
private final Point mMinSize = new Point();
@@ -404,6 +405,10 @@
public void setImeVisibility(boolean imeShowing, int imeHeight) {
mIsImeShowing = imeShowing;
mImeHeight = imeHeight;
+ // If IME is showing, save the current PiP bounds in case we need to restore it later.
+ if (mIsImeShowing) {
+ mRestoreBounds.set(getBounds());
+ }
}
/** Returns whether the IME is currently showing. */
@@ -411,6 +416,16 @@
return mIsImeShowing;
}
+ /** Returns the bounds to restore PiP to (bounds before IME was expanded). */
+ public Rect getRestoreBounds() {
+ return mRestoreBounds;
+ }
+
+ /** Sets mRestoreBounds to (0,0,0,0). */
+ public void clearRestoreBounds() {
+ mRestoreBounds.setEmpty();
+ }
+
/** Returns the IME height. */
public int getImeHeight() {
return mImeHeight;
@@ -521,6 +536,10 @@
/** Set whether the user has resized the PIP. */
public void setHasUserResizedPip(boolean hasUserResizedPip) {
mHasUserResizedPip = hasUserResizedPip;
+ // If user resized PiP while IME is showing, clear the pre-IME restore bounds.
+ if (hasUserResizedPip && isImeShowing()) {
+ clearRestoreBounds();
+ }
}
/** Returns whether the user has moved the PIP. */
@@ -531,6 +550,10 @@
/** Set whether the user has moved the PIP. */
public void setHasUserMovedPip(boolean hasUserMovedPip) {
mHasUserMovedPip = hasUserMovedPip;
+ // If user moved PiP while IME is showing, clear the pre-IME restore bounds.
+ if (hasUserMovedPip && isImeShowing()) {
+ clearRestoreBounds();
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 7054c17c..8c7dcf2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -18,6 +18,7 @@
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.content.Context;
@@ -114,6 +115,8 @@
import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+import com.android.wm.shell.windowdecor.viewhost.DefaultWindowDecorViewHostSupplier;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
import dagger.Binds;
import dagger.Lazy;
@@ -244,7 +247,8 @@
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
- Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler) {
+ Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
if (DesktopModeStatus.canEnterDesktopMode(context)) {
return new DesktopModeWindowDecorViewModel(
context,
@@ -268,7 +272,8 @@
assistContentRequester,
multiInstanceHelper,
desktopTasksLimiter,
- desktopActivityOrientationHandler);
+ desktopActivityOrientationHandler,
+ windowDecorViewHostSupplier);
}
return new CaptionWindowDecorViewModel(
context,
@@ -282,7 +287,8 @@
displayController,
rootTaskDisplayAreaOrganizer,
syncQueue,
- transitions);
+ transitions,
+ windowDecorViewHostSupplier);
}
@WMSingleton
@@ -371,6 +377,13 @@
context, shellInit, transitions, windowDecorViewModel);
}
+ @WMSingleton
+ @Provides
+ static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier(
+ @ShellMainThread @NonNull CoroutineScope mainScope) {
+ return new DefaultWindowDecorViewHostSupplier(mainScope);
+ }
+
//
// One handed mode
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 1d16980..7e96253 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -1077,45 +1077,47 @@
request.triggerTask != null
}
+ /** Open an existing instance of an app. */
+ fun openInstance(
+ callingTask: RunningTaskInfo,
+ requestedTaskId: Int
+ ) {
+ val wct = WindowContainerTransaction()
+ val options = createNewWindowOptions(callingTask)
+ if (options.launchWindowingMode == WINDOWING_MODE_FREEFORM) {
+ wct.startTask(requestedTaskId, options.toBundle())
+ transitions.startTransition(TRANSIT_OPEN, wct, null)
+ } else {
+ val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
+ splitScreenController.startTask(requestedTaskId, splitPosition,
+ options.toBundle(), null /* hideTaskToken */)
+ }
+ }
+
+ /** Create an Intent to open a new window of a task. */
fun openNewWindow(
- taskInfo: RunningTaskInfo
+ callingTaskInfo: RunningTaskInfo
) {
// TODO(b/337915660): Add a transition handler for these; animations
// need updates in some cases.
- val newTaskWindowingMode = when {
- taskInfo.isFreeform -> {
- WINDOWING_MODE_FREEFORM
- }
- taskInfo.isFullscreen || taskInfo.isMultiWindow -> {
- WINDOWING_MODE_MULTI_WINDOW
- }
- else -> {
- error("Invalid windowing mode: ${taskInfo.windowingMode}")
- }
- }
-
- val baseActivity = taskInfo.baseActivity ?: return
+ val baseActivity = callingTaskInfo.baseActivity ?: return
val fillIn: Intent = context.packageManager
.getLaunchIntentForPackage(
baseActivity.packageName
) ?: return
fillIn
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
- val options =
- ActivityOptions.makeBasic().apply {
- launchWindowingMode = newTaskWindowingMode
- pendingIntentBackgroundActivityStartMode =
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
- }
val launchIntent = PendingIntent.getActivity(
context,
/* requestCode= */ 0,
fillIn,
PendingIntent.FLAG_IMMUTABLE
)
- when (newTaskWindowingMode) {
+ val options = createNewWindowOptions(callingTaskInfo)
+ when (options.launchWindowingMode) {
WINDOWING_MODE_MULTI_WINDOW -> {
- val splitPosition = splitScreenController.determineNewInstancePosition(taskInfo)
+ val splitPosition = splitScreenController
+ .determineNewInstancePosition(callingTaskInfo)
splitScreenController.startIntent(
launchIntent, context.userId, fillIn, splitPosition,
options.toBundle(), null /* hideTaskToken */
@@ -1130,6 +1132,25 @@
}
}
+ private fun createNewWindowOptions(callingTask: RunningTaskInfo): ActivityOptions {
+ val newTaskWindowingMode = when {
+ callingTask.isFreeform -> {
+ WINDOWING_MODE_FREEFORM
+ }
+ callingTask.isFullscreen || callingTask.isMultiWindow -> {
+ WINDOWING_MODE_MULTI_WINDOW
+ }
+ else -> {
+ error("Invalid windowing mode: ${callingTask.windowingMode}")
+ }
+ }
+ return ActivityOptions.makeBasic().apply {
+ launchWindowingMode = newTaskWindowingMode
+ pendingIntentBackgroundActivityStartMode =
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+ }
+ }
+
/**
* Handles the case where a freeform task is launched from recents.
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index d72ec90..dfc5ab3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -629,15 +629,20 @@
finishTransaction: SurfaceControl.Transaction?
) {
val state = transitionState ?: return
- if (aborted && state.startTransitionToken == transition) {
+ if (!aborted) {
+ return
+ }
+ if (state.startTransitionToken == transition) {
ProtoLog.v(
ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"DragToDesktop: onTransitionConsumed() start transition aborted"
)
state.startAborted = true
- // Cancel CUJ interaction if the transition is aborted.
+ // The start-transition (DRAG_HOLD) is aborted, cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
} else if (state.cancelTransitionToken != transition) {
+ // This transition being aborted is neither the start, nor the cancel transition, so
+ // it must be the finish transition (DRAG_RELEASE); cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index cf02fb5..22e8dc1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -26,7 +26,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
@@ -247,9 +246,8 @@
R.layout.global_drop_target, null);
rootView.setOnDragListener(this);
rootView.setVisibility(View.INVISIBLE);
- DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
- rootView.addView(dragLayout,
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ DragLayoutProvider dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
+ dragLayout.addDraggingView(rootView);
try {
wm.addView(rootView, layoutParams);
addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
@@ -261,7 +259,7 @@
@VisibleForTesting
void addDisplayDropTarget(int displayId, Context context, WindowManager wm,
- FrameLayout rootView, DragLayout dragLayout) {
+ FrameLayout rootView, DragLayoutProvider dragLayout) {
mDisplayDropTargets.put(displayId,
new PerDisplay(displayId, context, wm, rootView, dragLayout));
}
@@ -564,7 +562,7 @@
final Context context;
final WindowManager wm;
final FrameLayout rootView;
- final DragLayout dragLayout;
+ final DragLayoutProvider dragLayout;
// Tracks whether the window has fully drawn since it was last made visible
boolean hasDrawn;
@@ -575,7 +573,7 @@
// The active drag session
DragSession dragSession;
- PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
+ PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayoutProvider dl) {
displayId = dispId;
context = c;
wm = w;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 3fecbe7..dfa2437 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -23,10 +23,10 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -47,6 +47,7 @@
import android.graphics.drawable.Drawable;
import android.view.DragEvent;
import android.view.SurfaceControl;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
@@ -66,13 +67,13 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
-import java.util.ArrayList;
+import java.util.List;
/**
* Coordinates the visible drop targets for the current drag within a single display.
*/
public class DragLayout extends LinearLayout
- implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ implements ViewTreeObserver.OnComputeInternalInsetsListener, DragLayoutProvider {
// While dragging the status bar is hidden.
private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
@@ -80,7 +81,7 @@
| StatusBarManager.DISABLE_CLOCK
| StatusBarManager.DISABLE_SYSTEM_INFO;
- private final DragAndDropPolicy mPolicy;
+ private final DropTarget mPolicy;
private final SplitScreenController mSplitScreenController;
private final IconProvider mIconProvider;
private final StatusBarManager mStatusBarManager;
@@ -91,7 +92,7 @@
// Whether the device is currently in left/right split mode
private boolean mIsLeftRightSplit;
- private DragAndDropPolicy.Target mCurrentTarget = null;
+ private SplitDragPolicy.Target mCurrentTarget = null;
private DropZoneView mDropZoneView1;
private DropZoneView mDropZoneView2;
@@ -113,7 +114,7 @@
super(context);
mSplitScreenController = splitScreenController;
mIconProvider = iconProvider;
- mPolicy = new DragAndDropPolicy(context, splitScreenController);
+ mPolicy = new SplitDragPolicy(context, splitScreenController);
mStatusBarManager = context.getSystemService(StatusBarManager.class);
mLastConfiguration.setTo(context.getResources().getConfiguration());
@@ -387,6 +388,13 @@
recomputeDropTargets();
}
+ @NonNull
+ @Override
+ public void addDraggingView(ViewGroup rootView) {
+ // TODO(b/349828130) We need to separate out view + logic here
+ rootView.addView(this, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
+
/**
* Recalculates the drop targets based on the current policy.
*/
@@ -394,9 +402,9 @@
if (!mIsShowing) {
return;
}
- final ArrayList<DragAndDropPolicy.Target> targets = mPolicy.getTargets(mInsets);
+ final List<SplitDragPolicy.Target> targets = mPolicy.getTargets(mInsets);
for (int i = 0; i < targets.size(); i++) {
- final DragAndDropPolicy.Target target = targets.get(i);
+ final SplitDragPolicy.Target target = targets.get(i);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", target);
// Inset the draw region by a little bit
target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
@@ -419,7 +427,7 @@
}
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
// visibility of the current region
- DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
+ SplitDragPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
if (mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
if (target == null) {
@@ -493,7 +501,7 @@
mHasDropped = true;
// Process the drop
- mPolicy.handleDrop(mCurrentTarget, hideTaskToken);
+ mPolicy.onDropped(mCurrentTarget, hideTaskToken);
// Start animating the drop UI out with the drag surface
hide(event, dropCompleteCallback);
@@ -576,7 +584,7 @@
}
}
- private void animateHighlight(DragAndDropPolicy.Target target) {
+ private void animateHighlight(SplitDragPolicy.Target target) {
if (target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP) {
mDropZoneView1.setShowingHighlight(true);
mDropZoneView2.setShowingHighlight(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt
new file mode 100644
index 0000000..3d40824
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.draganddrop
+
+import android.content.res.Configuration
+import android.view.DragEvent
+import android.view.SurfaceControl
+import android.view.ViewGroup
+import android.window.WindowContainerToken
+import com.android.internal.logging.InstanceId
+import java.io.PrintWriter
+
+/** Interface to be implemented by any controllers providing a layout for DragAndDrop in Shell */
+interface DragLayoutProvider {
+ /**
+ * Updates the drag layout based on the given drag session.
+ */
+ fun updateSession(session: DragSession)
+ /**
+ * Called when a new drag is started.
+ */
+ fun prepare(session: DragSession, loggerSessionId: InstanceId?)
+
+ /**
+ * Shows the drag layout.
+ */
+ fun show()
+
+ /**
+ * Updates the visible drop target as the user drags.
+ */
+ fun update(event: DragEvent?)
+
+ /**
+ * Hides the drag layout and animates out the visible drop targets.
+ */
+ fun hide(event: DragEvent?, hideCompleteCallback: Runnable?)
+
+ /**
+ * Whether target has already been dropped or not
+ */
+ fun hasDropped(): Boolean
+
+ /**
+ * Handles the drop onto a target and animates out the visible drop targets.
+ */
+ fun drop(
+ event: DragEvent?, dragSurface: SurfaceControl,
+ hideTaskToken: WindowContainerToken?, dropCompleteCallback: Runnable?
+ ): Boolean
+
+ /**
+ * Dumps information about this drag layout.
+ */
+ fun dump(pw: PrintWriter, prefix: String?)
+
+ /**
+ * @return a View which will be added to the global root view for drag and drop
+ */
+ fun addDraggingView(viewGroup: ViewGroup)
+
+ /**
+ * Called when the configuration changes.
+ */
+ fun onConfigChanged(newConfig: Configuration?)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
new file mode 100644
index 0000000..122a105
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.draganddrop
+
+import android.graphics.Insets
+import android.window.WindowContainerToken
+import com.android.internal.logging.InstanceId
+
+/**
+ * Interface to be implemented by classes which want to provide drop targets
+ * for DragAndDrop in Shell
+ */
+interface DropTarget {
+ // TODO(b/349828130) Delete after flexible split launches
+ /**
+ * Called at the start of a Drag, before input events are processed.
+ */
+ fun start(dragSession: DragSession, logSessionId: InstanceId)
+ /**
+ * @return [SplitDragPolicy.Target] corresponding to the given coords in display bounds.
+ */
+ fun getTargetAtLocation(x: Int, y: Int) : SplitDragPolicy.Target
+ /**
+ * @return total number of drop targets for the current drag session.
+ */
+ fun getNumTargets() : Int
+ // TODO(b/349828130)
+
+ /**
+ * @return [List<SplitDragPolicy.Target>] to show for the current drag session.
+ */
+ fun getTargets(insets: Insets) : List<SplitDragPolicy.Target>
+ /**
+ * Called when user is hovering Drag object over the given Target
+ */
+ fun onHoveringOver(target: SplitDragPolicy.Target) {}
+ /**
+ * Called when the user has dropped the provided target (need not be the same target as
+ * [onHoveringOver])
+ */
+ fun onDropped(target: SplitDragPolicy.Target, hideTaskToken: WindowContainerToken)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
similarity index 93%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
index 6fec0c1..2a19d65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
@@ -32,11 +32,11 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -80,9 +80,9 @@
/**
* The policy for handling drag and drop operations to shell.
*/
-public class DragAndDropPolicy {
+public class SplitDragPolicy implements DropTarget {
- private static final String TAG = DragAndDropPolicy.class.getSimpleName();
+ private static final String TAG = SplitDragPolicy.class.getSimpleName();
private final Context mContext;
// Used only for launching a fullscreen task (or as a fallback if there is no split starter)
@@ -90,18 +90,18 @@
// Used for launching tasks into splitscreen
private final Starter mSplitscreenStarter;
private final SplitScreenController mSplitScreen;
- private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
+ private final ArrayList<SplitDragPolicy.Target> mTargets = new ArrayList<>();
private final RectF mDisallowHitRegion = new RectF();
private InstanceId mLoggerSessionId;
private DragSession mSession;
- public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
+ public SplitDragPolicy(Context context, SplitScreenController splitScreen) {
this(context, splitScreen, new DefaultStarter(context));
}
@VisibleForTesting
- DragAndDropPolicy(Context context, SplitScreenController splitScreen,
+ SplitDragPolicy(Context context, SplitScreenController splitScreen,
Starter fullscreenStarter) {
mContext = context;
mSplitScreen = splitScreen;
@@ -112,7 +112,7 @@
/**
* Starts a new drag session with the given initial drag data.
*/
- void start(DragSession session, InstanceId loggerSessionId) {
+ public void start(DragSession session, InstanceId loggerSessionId) {
mLoggerSessionId = loggerSessionId;
mSession = session;
RectF disallowHitRegion = mSession.appData != null
@@ -128,7 +128,8 @@
/**
* Returns the number of targets.
*/
- int getNumTargets() {
+ @Override
+ public int getNumTargets() {
return mTargets.size();
}
@@ -136,7 +137,8 @@
* Returns the target's regions based on the current state of the device and display.
*/
@NonNull
- ArrayList<Target> getTargets(Insets insets) {
+ @Override
+ public ArrayList<Target> getTargets(@NonNull Insets insets) {
mTargets.clear();
if (mSession == null) {
// Return early if this isn't an app drag
@@ -222,12 +224,12 @@
* Returns the target at the given position based on the targets previously calculated.
*/
@Nullable
- Target getTargetAtLocation(int x, int y) {
+ public Target getTargetAtLocation(int x, int y) {
if (mDisallowHitRegion.contains(x, y)) {
return null;
}
for (int i = mTargets.size() - 1; i >= 0; i--) {
- DragAndDropPolicy.Target t = mTargets.get(i);
+ SplitDragPolicy.Target t = mTargets.get(i);
if (t.hitRegion.contains(x, y)) {
return t;
}
@@ -241,7 +243,7 @@
* container transaction if possible.
*/
@VisibleForTesting
- void handleDrop(Target target, @Nullable WindowContainerToken hideTaskToken) {
+ public void onDropped(Target target, @Nullable WindowContainerToken hideTaskToken) {
if (target == null || !mTargets.contains(target)) {
return;
}
@@ -419,8 +421,9 @@
/**
* Represents a drop target.
+ * TODO(b/349828130): Move this into {@link DropTarget}
*/
- static class Target {
+ public static class Target {
static final int TYPE_FULLSCREEN = 0;
static final int TYPE_SPLIT_LEFT = 1;
static final int TYPE_SPLIT_TOP = 2;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index ab222c9..b4e0329 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -2033,7 +2033,10 @@
tx.apply();
}
- private void cancelCurrentAnimator() {
+ /**
+ * Cancels the currently running animator if there is one and removes an overlay if present.
+ */
+ public void cancelCurrentAnimator() {
final PipAnimationController.PipTransitionAnimator<?> animator =
mPipAnimationController.getCurrentAnimator();
// remove any overlays if present
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 755e958..deb7691 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -324,7 +324,7 @@
return;
}
onDisplayChanged(mDisplayController.getDisplayLayout(displayId),
- false /* saveRestoreSnapFraction */);
+ true /* saveRestoreSnapFraction */);
}
@Override
@@ -652,9 +652,11 @@
// there's a keyguard present
return;
}
- onDisplayChangedUncheck(mDisplayController
- .getDisplayLayout(mPipDisplayLayoutState.getDisplayId()),
- false /* saveRestoreSnapFraction */);
+ mMainExecutor.executeDelayed(() -> {
+ onDisplayChangedUncheck(mDisplayController.getDisplayLayout(
+ mPipDisplayLayoutState.getDisplayId()),
+ false /* saveRestoreSnapFraction */);
+ }, PIP_KEEP_CLEAR_AREAS_DELAY);
}
});
@@ -800,7 +802,7 @@
}
};
- if (mPipTaskOrganizer.isInPip() && saveRestoreSnapFraction) {
+ if (mPipTransitionState.hasEnteredPip() && saveRestoreSnapFraction) {
mMenuController.attachPipMenuView();
// Calculate the snap fraction of the current stack along the old movement bounds
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 793e2aa..87b661d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -92,7 +92,7 @@
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.draganddrop.DragAndDropController;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.draganddrop.SplitDragPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.shared.TransactionPool;
@@ -121,7 +121,7 @@
* @see StageCoordinator
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
-public class SplitScreenController implements DragAndDropPolicy.Starter,
+public class SplitScreenController implements SplitDragPolicy.Starter,
RemoteCallable<SplitScreenController>, KeyguardChangeListener {
private static final String TAG = SplitScreenController.class.getSimpleName();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 1b143eb..4ba84ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -34,7 +34,6 @@
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
-import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
@@ -1668,7 +1667,6 @@
if (mRootTaskInfo == null || mRootTaskInfo.taskId != taskInfo.taskId) {
throw new IllegalArgumentException(this + "\n Unknown task info changed: " + taskInfo);
}
- mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
mRootTaskInfo = taskInfo;
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
@@ -2822,6 +2820,10 @@
mSplitLayout.flingDividerToCenter(this::notifySplitAnimationFinished);
}
callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
+ mWindowDecorViewModel.ifPresent(viewModel -> {
+ viewModel.onTaskInfoChanged(finalMainChild.getTaskInfo());
+ viewModel.onTaskInfoChanged(finalSideChild.getTaskInfo());
+ });
mPausingTasks.clear();
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 11976ae..0151395 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -62,6 +62,7 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
/**
* View model for the window decoration with a caption and shadows. Works with
@@ -83,6 +84,7 @@
private final Transitions mTransitions;
private final Region mExclusionRegion = Region.obtain();
private final InputManager mInputManager;
+ private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
private TaskOperations mTaskOperations;
/**
@@ -120,7 +122,8 @@
DisplayController displayController,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
SyncTransactionQueue syncQueue,
- Transitions transitions) {
+ Transitions transitions,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
mContext = context;
mMainExecutor = shellExecutor;
mMainHandler = mainHandler;
@@ -132,6 +135,7 @@
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mSyncQueue = syncQueue;
mTransitions = transitions;
+ mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
}
@@ -295,7 +299,8 @@
mMainHandler,
mBgExecutor,
mMainChoreographer,
- mSyncQueue);
+ mSyncQueue,
+ mWindowDecorViewHostSupplier);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final FluidResizeTaskPositioner taskPositioner =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 349ee0b..46fe68f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -56,6 +56,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -88,8 +89,10 @@
Handler handler,
@ShellBackgroundThread ShellExecutor bgExecutor,
Choreographer choreographer,
- SyncTransactionQueue syncQueue) {
- super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface);
+ SyncTransactionQueue syncQueue,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
+ super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
+ windowDecorViewHostSupplier);
mHandler = handler;
mBgExecutor = bgExecutor;
mChoreographer = choreographer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
new file mode 100644
index 0000000..13a805a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.Context
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.WindowManager
+import android.window.TaskSnapshot
+import androidx.compose.ui.graphics.toArgb
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import com.android.wm.shell.shared.split.SplitScreenConstants
+import com.android.wm.shell.splitscreen.SplitScreenController
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
+import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import com.android.wm.shell.windowdecor.extension.isFullscreen
+import com.android.wm.shell.windowdecor.extension.isMultiWindow
+
+/**
+ * Implementation of [ManageWindowsViewContainer] meant to be used in desktop header and app
+ * handle.
+ */
+class DesktopHandleManageWindowsMenu(
+ private val callerTaskInfo: RunningTaskInfo,
+ private val splitScreenController: SplitScreenController,
+ private val captionX: Int,
+ private val captionWidth: Int,
+ private val windowManagerWrapper: WindowManagerWrapper,
+ context: Context,
+ snapshotList: List<Pair<Int, TaskSnapshot>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)
+) : ManageWindowsViewContainer(
+ context,
+ DecorThemeUtil(context).getColorScheme(callerTaskInfo).background.toArgb()
+) {
+ private var menuViewContainer: AdditionalViewContainer? = null
+
+ init {
+ show(snapshotList, onIconClickListener, onOutsideClickListener)
+ }
+
+ override fun close() {
+ menuViewContainer?.releaseView()
+ }
+
+ private fun calculateMenuPosition(): Point {
+ val position = Point()
+ val nonFreeformX = (captionX + (captionWidth / 2) - (menuView.menuWidth / 2))
+ when {
+ callerTaskInfo.isFreeform -> {
+ val taskBounds = callerTaskInfo.getConfiguration().windowConfiguration.bounds
+ position.set(taskBounds.left, taskBounds.top)
+ }
+ callerTaskInfo.isFullscreen -> {
+ position.set(nonFreeformX, 0)
+ }
+ callerTaskInfo.isMultiWindow -> {
+ val splitPosition = splitScreenController.getSplitPosition(callerTaskInfo.taskId)
+ val leftOrTopStageBounds = Rect()
+ val rightOrBottomStageBounds = Rect()
+ splitScreenController.getStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds)
+ // TODO(b/343561161): This needs to be calculated differently if the task is in
+ // top/bottom split.
+ when (splitPosition) {
+ SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> {
+ position.set(leftOrTopStageBounds.width() + nonFreeformX, /* y= */ 0)
+ }
+
+ SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> {
+ position.set(nonFreeformX, /* y= */ 0)
+ }
+ }
+ }
+ }
+ return position
+ }
+
+ override fun addToContainer(menuView: ManageWindowsView) {
+ val menuPosition = calculateMenuPosition()
+ menuViewContainer = AdditionalSystemViewContainer(
+ windowManagerWrapper,
+ callerTaskInfo.taskId,
+ menuPosition.x,
+ menuPosition.y,
+ menuView.menuWidth,
+ menuView.menuHeight,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ menuView.rootView
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
new file mode 100644
index 0000000..05391a8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import android.window.TaskConstants
+import android.window.TaskSnapshot
+import androidx.compose.ui.graphics.toArgb
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
+import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import java.util.function.Supplier
+
+/**
+ * Implementation of [ManageWindowsViewContainer] meant to be used in desktop header and app
+ * handle.
+ */
+class DesktopHeaderManageWindowsMenu(
+ private val callerTaskInfo: RunningTaskInfo,
+ private val displayController: DisplayController,
+ private val rootTdaOrganizer: RootTaskDisplayAreaOrganizer,
+ context: Context,
+ private val surfaceControlBuilderSupplier: Supplier<SurfaceControl.Builder>,
+ private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>,
+ snapshotList: List<Pair<Int, TaskSnapshot>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)
+) : ManageWindowsViewContainer(
+ context,
+ DecorThemeUtil(context).getColorScheme(callerTaskInfo).background.toArgb()
+) {
+ private var menuViewContainer: AdditionalViewContainer? = null
+
+ init {
+ show(snapshotList, onIconClickListener, onOutsideClickListener)
+ }
+
+ override fun close() {
+ menuViewContainer?.releaseView()
+ }
+
+ override fun addToContainer(menuView: ManageWindowsView) {
+ val taskBounds = callerTaskInfo.getConfiguration().windowConfiguration.bounds
+ val menuPosition = Point(taskBounds.left, taskBounds.top)
+ val builder = surfaceControlBuilderSupplier.get()
+ rootTdaOrganizer.attachToDisplayArea(callerTaskInfo.displayId, builder)
+ val leash = builder
+ .setName("Manage Windows Menu")
+ .setContainerLayer()
+ .build()
+ val lp = WindowManager.LayoutParams(
+ menuView.menuWidth, menuView.menuHeight,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSPARENT
+ )
+ val windowManager = WindowlessWindowManager(
+ callerTaskInfo.configuration,
+ leash,
+ null // HostInputToken
+ )
+ val viewHost = SurfaceControlViewHost(
+ context,
+ displayController.getDisplay(callerTaskInfo.displayId), windowManager,
+ "MaximizeMenu"
+ )
+ menuView.let { viewHost.setView(it.rootView, lp) }
+ val t = surfaceControlTransactionSupplier.get()
+ t.setLayer(leash, TaskConstants.TASK_CHILD_LAYER_FLOATING_MENU)
+ .setPosition(leash, menuPosition.x.toFloat(), menuPosition.y.toFloat())
+ .show(leash)
+ t.apply()
+ menuViewContainer = AdditionalViewHostViewContainer(
+ leash, viewHost,
+ surfaceControlTransactionSupplier
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 0f8bd28..2519ce4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -39,14 +39,18 @@
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+import static com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer.MANAGE_WINDOWS_MINIMUM_INSTANCES;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
+import android.app.IActivityManager;
+import android.app.IActivityTaskManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
@@ -76,6 +80,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.widget.Toast;
+import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -122,10 +127,14 @@
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
+import kotlin.Pair;
import kotlin.Unit;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
@@ -155,6 +164,7 @@
private final InteractionJankMonitor mInteractionJankMonitor;
private final MultiInstanceHelper mMultiInstanceHelper;
private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
+ private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
private boolean mTransitionDragActive;
private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
@@ -223,8 +233,8 @@
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
- Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler
- ) {
+ Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
this(
context,
shellExecutor,
@@ -244,6 +254,7 @@
genericLinksParser,
assistContentRequester,
multiInstanceHelper,
+ windowDecorViewHostSupplier,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
SurfaceControl.Transaction::new,
@@ -275,6 +286,7 @@
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
Supplier<SurfaceControl.Transaction> transactionFactory,
@@ -300,6 +312,7 @@
mMultiInstanceHelper = multiInstanceHelper;
mShellCommandHandler = shellCommandHandler;
mWindowManager = windowManager;
+ mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
mInputMonitorFactory = inputMonitorFactory;
mTransactionFactory = transactionFactory;
@@ -580,6 +593,61 @@
mDesktopTasksController.openNewWindow(decoration.mTaskInfo);
}
+ private void onManageWindows(DesktopModeWindowDecoration decoration) {
+ if (decoration == null) {
+ return;
+ }
+ decoration.closeHandleMenu();
+ decoration.createManageWindowsMenu(getTaskSnapshots(decoration.mTaskInfo),
+ /* onIconClickListener= */(Integer requestedTaskId) -> {
+ decoration.closeManageWindowsMenu();
+ mDesktopTasksController.openInstance(decoration.mTaskInfo, requestedTaskId);
+ return Unit.INSTANCE;
+ });
+ }
+
+ private ArrayList<Pair<Integer, TaskSnapshot>> getTaskSnapshots(
+ @NonNull RunningTaskInfo callerTaskInfo
+ ) {
+ final ArrayList<Pair<Integer, TaskSnapshot>> snapshotList = new ArrayList<>();
+ final IActivityManager activityManager = ActivityManager.getService();
+ final IActivityTaskManager activityTaskManagerService = ActivityTaskManager.getService();
+ final List<ActivityManager.RecentTaskInfo> recentTasks;
+ try {
+ recentTasks = mActivityTaskManager.getRecentTasks(
+ Integer.MAX_VALUE,
+ ActivityManager.RECENT_WITH_EXCLUDED,
+ activityManager.getCurrentUser().id);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ final String callerPackageName = callerTaskInfo.baseActivity.getPackageName();
+ for (ActivityManager.RecentTaskInfo info : recentTasks) {
+ if (info.taskId == callerTaskInfo.taskId || info.baseActivity == null) continue;
+ final String infoPackageName = info.baseActivity.getPackageName();
+ if (!infoPackageName.equals(callerPackageName)) {
+ continue;
+ }
+ if (info.baseActivity != null) {
+ if (callerPackageName.equals(infoPackageName)) {
+ // TODO(b/337903443): Fix this returning null for freeform tasks.
+ try {
+ TaskSnapshot screenshot = activityTaskManagerService
+ .getTaskSnapshot(info.taskId, false);
+ if (screenshot == null) {
+ screenshot = activityTaskManagerService
+ .takeTaskSnapshot(info.taskId, false);
+ }
+ snapshotList.add(new Pair(info.taskId, screenshot));
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+ return snapshotList;
+ }
+
private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
View.OnGenericMotionListener, DragDetector.MotionEventHandler {
@@ -636,7 +704,8 @@
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
moveTaskToFront(decoration.mTaskInfo);
- decoration.createHandleMenu();
+ decoration.createHandleMenu(checkNumberOfOtherInstances(decoration.mTaskInfo)
+ >= MANAGE_WINDOWS_MINIMUM_INSTANCES);
}
} else if (id == R.id.maximize_window) {
// TODO(b/346441962): move click detection logic into the decor's
@@ -1098,8 +1167,22 @@
// If we are entering split select, handle will no longer be visible and
// should not be receiving any input.
if (resultType == TO_SPLIT_LEFT_INDICATOR
- || resultType != TO_SPLIT_RIGHT_INDICATOR) {
+ || resultType == TO_SPLIT_RIGHT_INDICATOR) {
relevantDecor.disposeStatusBarInputLayer();
+ // We should also dispose the other split task's input layer if
+ // applicable.
+ final int splitPosition = mSplitScreenController
+ .getSplitPosition(relevantDecor.mTaskInfo.taskId);
+ if (splitPosition != SPLIT_POSITION_UNDEFINED) {
+ final int oppositePosition =
+ splitPosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? SPLIT_POSITION_BOTTOM_OR_RIGHT
+ : SPLIT_POSITION_TOP_OR_LEFT;
+ final RunningTaskInfo oppositeTaskInfo =
+ mSplitScreenController.getTaskInfo(oppositePosition);
+ mWindowDecorByTaskId.get(oppositeTaskInfo.taskId)
+ .disposeStatusBarInputLayer();
+ }
}
mMoveToDesktopAnimator = null;
return;
@@ -1284,7 +1367,8 @@
mRootTaskDisplayAreaOrganizer,
mGenericLinksParser,
mAssistContentRequester,
- mMultiInstanceHelper);
+ mMultiInstanceHelper,
+ mWindowDecorViewHostSupplier);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final TaskPositioner taskPositioner = mTaskPositionerFactory.create(
@@ -1329,6 +1413,10 @@
onNewWindow(taskInfo.taskId);
return Unit.INSTANCE;
});
+ windowDecoration.setManageWindowsClickListener(() -> {
+ onManageWindows(windowDecoration);
+ return Unit.INSTANCE;
+ });
windowDecoration.setCaptionListeners(
touchEventListener, touchEventListener, touchEventListener, touchEventListener);
windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
@@ -1420,6 +1508,29 @@
}
}
+ /**
+ * Gets the number of instances of a task running, not including the specified task itself.
+ */
+ private int checkNumberOfOtherInstances(@NonNull RunningTaskInfo info) {
+ // TODO(b/336289597): Rather than returning number of instances, return a list of valid
+ // instances, then refer to the list's size and reuse the list for Manage Windows menu.
+ final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
+ final IActivityManager activityManager = ActivityManager.getService();
+ try {
+ return activityTaskManager.getRecentTasks(Integer.MAX_VALUE,
+ ActivityManager.RECENT_WITH_EXCLUDED,
+ activityManager.getCurrentUserId()).getList().stream().filter(
+ recentTaskInfo -> (recentTaskInfo.taskId != info.taskId
+ && recentTaskInfo.baseActivity != null
+ && recentTaskInfo.baseActivity.getPackageName()
+ .equals(info.baseActivity.getPackageName())
+ )
+ ).toList().size();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
static class InputMonitorFactory {
InputMonitor create(InputManager inputManager, int displayId) {
return inputManager.monitorGestureInput("caption-touch", displayId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 142be91..5d16d97 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -35,7 +35,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.WindowConfiguration.WindowingMode;
import android.app.assist.AssistContent;
@@ -65,6 +64,7 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.ImageButton;
+import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
@@ -87,15 +87,20 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
+import kotlin.Pair;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
+import kotlin.jvm.functions.Function1;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -131,18 +136,18 @@
private Function0<Unit> mOnToFullscreenClickListener;
private Function0<Unit> mOnToSplitscreenClickListener;
private Function0<Unit> mOnNewWindowClickListener;
+ private Function0<Unit> mOnManageWindowsClickListener;
private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
- private Runnable mCurrentViewHostRunnable = null;
private RelayoutParams mRelayoutParams = new RelayoutParams();
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
new WindowDecoration.RelayoutResult<>();
- private final Runnable mViewHostRunnable =
- () -> updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mResult);
private final Point mPositionInParent = new Point();
private HandleMenu mHandleMenu;
+ private boolean mMinimumInstancesFound;
+ private ManageWindowsViewContainer mManageWindowsMenu;
private MaximizeMenu mMaximizeMenu;
@@ -190,14 +195,16 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
- MultiInstanceHelper multiInstanceHelper) {
+ MultiInstanceHelper multiInstanceHelper,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
this (context, userContext, displayController, splitScreenController, taskOrganizer,
taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue,
rootTaskDisplayAreaOrganizer, genericLinksParser, assistContentRequester,
SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(
context.getSystemService(WindowManager.class)),
- new SurfaceControlViewHostFactory() {}, DefaultMaximizeMenuFactory.INSTANCE,
+ new SurfaceControlViewHostFactory() {}, windowDecorViewHostSupplier,
+ DefaultMaximizeMenuFactory.INSTANCE,
DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper);
}
@@ -222,13 +229,14 @@
Supplier<SurfaceControl> surfaceControlSupplier,
WindowManagerWrapper windowManagerWrapper,
SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier,
MaximizeMenuFactory maximizeMenuFactory,
HandleMenuFactory handleMenuFactory,
MultiInstanceHelper multiInstanceHelper) {
super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
windowContainerTransactionSupplier, surfaceControlSupplier,
- surfaceControlViewHostFactory);
+ surfaceControlViewHostFactory, windowDecorViewHostSupplier);
mSplitScreenController = splitScreenController;
mHandler = handler;
mBgExecutor = bgExecutor;
@@ -285,6 +293,14 @@
mOnNewWindowClickListener = listener;
}
+ /**
+ * Registers a listener to be called when the decoration's manage windows action is
+ * triggered.
+ */
+ void setManageWindowsClickListener(Function0<Unit> listener) {
+ mOnManageWindowsClickListener = listener;
+ }
+
void setCaptionListeners(
View.OnClickListener onCaptionButtonClickListener,
View.OnTouchListener onCaptionTouchListener,
@@ -337,73 +353,6 @@
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
Trace.beginSection("DesktopModeWindowDecoration#relayout");
- if (taskInfo.isFreeform()) {
- // The Task is in Freeform mode -> show its header in sync since it's an integral part
- // of the window itself - a delayed header might cause bad UX.
- relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop);
- } else {
- // The Task is outside Freeform mode -> allow the handle view to be delayed since the
- // handle is just a small addition to the window.
- relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop);
- }
- Trace.endSection();
- }
-
- /** Run the whole relayout phase immediately without delay. */
- private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo,
- SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
- // Clear the current ViewHost runnable as we will update the ViewHost here
- clearCurrentViewHostRunnable();
- updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop);
- if (mResult.mRootView != null) {
- updateViewHost(mRelayoutParams, startT, mResult);
- }
- }
-
- /**
- * Clear the current ViewHost runnable - to ensure it doesn't run once relayout params have been
- * updated.
- */
- private void clearCurrentViewHostRunnable() {
- if (mCurrentViewHostRunnable != null) {
- mHandler.removeCallbacks(mCurrentViewHostRunnable);
- mCurrentViewHostRunnable = null;
- }
- }
-
- /**
- * Relayout the window decoration but repost some of the work, to unblock the current callstack.
- */
- private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo,
- SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
- if (applyStartTransactionOnDraw) {
- throw new IllegalArgumentException(
- "We cannot both sync viewhost ondraw and delay viewhost creation.");
- }
- // Clear the current ViewHost runnable as we will update the ViewHost here
- clearCurrentViewHostRunnable();
- updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT,
- false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop);
- if (mResult.mRootView == null) {
- // This means something blocks the window decor from showing, e.g. the task is hidden.
- // Nothing is set up in this case including the decoration surface.
- return;
- }
- // Store the current runnable so it can be removed if we start a new relayout.
- mCurrentViewHostRunnable = mViewHostRunnable;
- mHandler.post(mCurrentViewHostRunnable);
- }
-
- @SuppressLint("MissingPermission")
- private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo,
- SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
- Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces");
if (Flags.enableDesktopWindowingAppToWeb()) {
setCapturedLink(taskInfo.capturedLink, taskInfo.capturedLinkTimestamp);
@@ -420,8 +369,8 @@
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- Trace.beginSection("DesktopModeWindowDecoration#relayout-updateViewsAndSurfaces");
- updateViewsAndSurfaces(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
+ Trace.beginSection("DesktopModeWindowDecoration#relayout-inner");
+ relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
Trace.endSection();
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
@@ -433,7 +382,7 @@
// This means something blocks the window decor from showing, e.g. the task is hidden.
// Nothing is set up in this case including the decoration surface.
disposeStatusBarInputLayer();
- Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces
+ Trace.endSection(); // DesktopModeWindowDecoration#relayout
return;
}
@@ -441,12 +390,12 @@
disposeStatusBarInputLayer();
mWindowDecorViewHolder = createViewHolder();
}
- Trace.beginSection("DesktopModeWindowDecoration#relayout-binding");
final Point position = new Point();
if (isAppHandle(mWindowDecorViewHolder)) {
position.set(determineHandlePosition());
}
+ Trace.beginSection("DesktopModeWindowDecoration#relayout-bindData");
mWindowDecorViewHolder.bindData(mTaskInfo,
position,
mResult.mCaptionWidth,
@@ -460,7 +409,7 @@
}
updateDragResizeListener(oldDecorationSurface);
updateMaximizeMenu(startT);
- Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces
+ Trace.endSection(); // DesktopModeWindowDecoration#relayout
}
private boolean isCaptionVisible() {
@@ -638,6 +587,10 @@
relayoutParams.mLayoutResId = captionLayoutId;
relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
+ // Allow the handle view to be delayed since the handle is just a small addition to the
+ // window, whereas the header cannot be delayed because it is expected to be visible from
+ // the first frame.
+ relayoutParams.mAsyncViewHost = isAppHandle;
if (isAppHeader) {
if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
@@ -1004,9 +957,10 @@
/**
* Updates app info and creates and displays handle menu window.
*/
- void createHandleMenu() {
+ void createHandleMenu(boolean minimumInstancesFound) {
// Requests assist content. When content is received, calls {@link #onAssistContentReceived}
// which sets app info and creates the handle menu.
+ mMinimumInstancesFound = minimumInstancesFound;
mAssistContentRequester.requestAssistContent(
mTaskInfo.taskId, this::onAssistContentReceived);
}
@@ -1019,8 +973,10 @@
mWebUri = assistContent == null ? null : assistContent.getWebUri();
loadAppInfoIfNeeded();
updateGenericLink();
-
- // Create and display handle menu
+ final boolean supportsMultiInstance = mMultiInstanceHelper
+ .supportsMultiInstanceSplit(mTaskInfo.baseActivity);
+ final boolean shouldShowManageWindowsButton = supportsMultiInstance
+ && mMinimumInstancesFound;
mHandleMenu = mHandleMenuFactory.create(
this,
mWindowManagerWrapper,
@@ -1029,9 +985,8 @@
mAppName,
mSplitScreenController,
DesktopModeStatus.canEnterDesktopMode(mContext),
- Flags.enableDesktopWindowingMultiInstanceFeatures()
- && mMultiInstanceHelper
- .supportsMultiInstanceSplit(mTaskInfo.baseActivity),
+ supportsMultiInstance,
+ shouldShowManageWindowsButton,
getBrowserLink(),
mResult.mCaptionWidth,
mResult.mCaptionHeight,
@@ -1047,6 +1002,7 @@
/* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
/* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener,
/* onNewWindowClickListener= */ mOnNewWindowClickListener,
+ /* onManageWindowsClickListener= */ mOnManageWindowsClickListener,
/* openInBrowserClickListener= */ (uri) -> {
mOpenInBrowserClickListener.accept(uri);
onCapturedLinkExpired();
@@ -1061,6 +1017,47 @@
return Unit.INSTANCE;
}
);
+ mMinimumInstancesFound = false;
+ }
+
+ void createManageWindowsMenu(@NonNull List<Pair<Integer, TaskSnapshot>> snapshotList,
+ @NonNull Function1<Integer, Unit> onIconClickListener
+ ) {
+ if (mTaskInfo.isFreeform()) {
+ mManageWindowsMenu = new DesktopHeaderManageWindowsMenu(
+ mTaskInfo,
+ mDisplayController,
+ mRootTaskDisplayAreaOrganizer,
+ mContext,
+ mSurfaceControlBuilderSupplier,
+ mSurfaceControlTransactionSupplier,
+ snapshotList,
+ onIconClickListener,
+ /* onOutsideClickListener= */ () -> {
+ closeManageWindowsMenu();
+ return Unit.INSTANCE;
+ }
+ );
+ } else {
+ mManageWindowsMenu = new DesktopHandleManageWindowsMenu(
+ mTaskInfo,
+ mSplitScreenController,
+ getCaptionX(),
+ mResult.mCaptionWidth,
+ mWindowManagerWrapper,
+ mContext,
+ snapshotList,
+ onIconClickListener,
+ /* onOutsideClickListener= */ () -> {
+ closeManageWindowsMenu();
+ return Unit.INSTANCE;
+ }
+ );
+ }
+ }
+
+ void closeManageWindowsMenu() {
+ mManageWindowsMenu.close();
}
private void updateGenericLink() {
@@ -1253,7 +1250,6 @@
mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
disposeResizeVeil();
disposeStatusBarInputLayer();
- clearCurrentViewHostRunnable();
super.close();
}
@@ -1364,7 +1360,8 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
- MultiInstanceHelper multiInstanceHelper) {
+ MultiInstanceHelper multiInstanceHelper,
+ WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
return new DesktopModeWindowDecoration(
context,
userContext,
@@ -1380,7 +1377,8 @@
rootTaskDisplayAreaOrganizer,
genericLinksParser,
assistContentRequester,
- multiInstanceHelper);
+ multiInstanceHelper,
+ windowDecorViewHostSupplier);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
new file mode 100644
index 0000000..e8131a0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.graphics.PointF
+import android.graphics.Rect
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CtrlType
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * [AbstractTaskPositionerDecorator] implementation for validating the coordinates associated with a
+ * drag action, to maintain a fixed aspect ratio before being used by the task positioner.
+ */
+class FixedAspectRatioTaskPositionerDecorator (
+ private val windowDecoration: DesktopModeWindowDecoration,
+ decoratedTaskPositioner: TaskPositioner
+) : AbstractTaskPositionerDecorator(decoratedTaskPositioner) {
+
+ private var originalCtrlType = CTRL_TYPE_UNDEFINED
+ private var edgeResizeCtrlType = CTRL_TYPE_UNDEFINED
+ private val lastRepositionedBounds = Rect()
+ private val startingPoint = PointF()
+ private val lastValidPoint = PointF()
+ private var startingAspectRatio = 0f
+ private var isTaskPortrait = false
+
+ override fun onDragPositioningStart(@CtrlType ctrlType: Int, x: Float, y: Float): Rect {
+ originalCtrlType = ctrlType
+ if (!requiresFixedAspectRatio()) {
+ return super.onDragPositioningStart(originalCtrlType, x, y)
+ }
+
+ lastRepositionedBounds.set(
+ windowDecoration.mTaskInfo.configuration.windowConfiguration.bounds)
+ startingPoint.set(x, y)
+ lastValidPoint.set(x, y)
+ val startingBoundWidth = lastRepositionedBounds.width()
+ val startingBoundHeight = lastRepositionedBounds.height()
+ startingAspectRatio = max(startingBoundWidth, startingBoundHeight).toFloat() /
+ min(startingBoundWidth, startingBoundHeight).toFloat()
+ isTaskPortrait = startingBoundWidth <= startingBoundHeight
+
+ lastRepositionedBounds.set(
+ when (originalCtrlType) {
+ // If resize in an edge resize, adjust ctrlType passed to onDragPositioningStart() to
+ // mimic a corner resize instead. As at lest two adjacent edges need to be resized
+ // in relation to each other to maintain the apps aspect ratio. The additional adjacent
+ // edge is selected based on its proximity (closest) to the start of the drag.
+ CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> {
+ val verticalMidPoint = lastRepositionedBounds.top + (startingBoundHeight / 2)
+ edgeResizeCtrlType = originalCtrlType +
+ if (y < verticalMidPoint) CTRL_TYPE_TOP else CTRL_TYPE_BOTTOM
+ super.onDragPositioningStart(edgeResizeCtrlType, x, y)
+ }
+ CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> {
+ val horizontalMidPoint = lastRepositionedBounds.left + (startingBoundWidth / 2)
+ edgeResizeCtrlType = originalCtrlType +
+ if (x < horizontalMidPoint) CTRL_TYPE_LEFT else CTRL_TYPE_RIGHT
+ super.onDragPositioningStart(edgeResizeCtrlType, x, y)
+ }
+ // If resize is corner resize, no alteration to the ctrlType needs to be made.
+ else -> {
+ edgeResizeCtrlType = CTRL_TYPE_UNDEFINED
+ super.onDragPositioningStart(originalCtrlType, x, y)
+ }
+ }
+ )
+ return lastRepositionedBounds
+ }
+
+ override fun onDragPositioningMove(x: Float, y: Float): Rect {
+ if (!requiresFixedAspectRatio()) {
+ return super.onDragPositioningMove(x, y)
+ }
+
+ val diffX = x - lastValidPoint.x
+ val diffY = y - lastValidPoint.y
+ when (originalCtrlType) {
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, CTRL_TYPE_TOP + CTRL_TYPE_LEFT -> {
+ if ((diffX > 0 && diffY > 0) || (diffX < 0 && diffY < 0)) {
+ // Drag coordinate falls within valid region (90 - 180 degrees or 270- 360
+ // degrees from the corner the previous valid point). Allow resize with adjusted
+ // coordinates to maintain aspect ratio.
+ lastRepositionedBounds.set(dragAdjustedMove(x, y))
+ }
+ }
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> {
+ if ((diffX > 0 && diffY < 0) || (diffX < 0 && diffY > 0)) {
+ // Drag coordinate falls within valid region (180 - 270 degrees or 0 - 90
+ // degrees from the corner the previous valid point). Allow resize with adjusted
+ // coordinates to maintain aspect ratio.
+ lastRepositionedBounds.set(dragAdjustedMove(x, y))
+ }
+ }
+ CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> {
+ // If resize is on left or right edge, always adjust the y coordinate.
+ val adjustedY = getScaledChangeForY(x)
+ lastValidPoint.set(x, adjustedY)
+ lastRepositionedBounds.set(super.onDragPositioningMove(x, adjustedY))
+ }
+ CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> {
+ // If resize is on top or bottom edge, always adjust the x coordinate.
+ val adjustedX = getScaledChangeForX(y)
+ lastValidPoint.set(adjustedX, y)
+ lastRepositionedBounds.set(super.onDragPositioningMove(adjustedX, y))
+ }
+ }
+ return lastRepositionedBounds
+ }
+
+ override fun onDragPositioningEnd(x: Float, y: Float): Rect {
+ if (!requiresFixedAspectRatio()) {
+ return super.onDragPositioningEnd(x, y)
+ }
+
+ val diffX = x - lastValidPoint.x
+ val diffY = y - lastValidPoint.y
+
+ when (originalCtrlType) {
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, CTRL_TYPE_TOP + CTRL_TYPE_LEFT -> {
+ if ((diffX > 0 && diffY > 0) || (diffX < 0 && diffY < 0)) {
+ // Drag coordinate falls within valid region (90 - 180 degrees or 270- 360
+ // degrees from the corner the previous valid point). End resize with adjusted
+ // coordinates to maintain aspect ratio.
+ return dragAdjustedEnd(x, y)
+ }
+ // If end of resize is not within valid region, end resize from last valid
+ // coordinates.
+ return super.onDragPositioningEnd(lastValidPoint.x, lastValidPoint.y)
+ }
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> {
+ if ((diffX > 0 && diffY < 0) || (diffX < 0 && diffY > 0)) {
+ // Drag coordinate falls within valid region (180 - 260 degrees or 0 - 90
+ // degrees from the corner the previous valid point). End resize with adjusted
+ // coordinates to maintain aspect ratio.
+ return dragAdjustedEnd(x, y)
+ }
+ // If end of resize is not within valid region, end resize from last valid
+ // coordinates.
+ return super.onDragPositioningEnd(lastValidPoint.x, lastValidPoint.y)
+ }
+ CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> {
+ // If resize is on left or right edge, always adjust the y coordinate.
+ return super.onDragPositioningEnd(x, getScaledChangeForY(x))
+ }
+ CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> {
+ // If resize is on top or bottom edge, always adjust the x coordinate.
+ return super.onDragPositioningEnd(getScaledChangeForX(y), y)
+ }
+ else -> {
+ return super.onDragPositioningEnd(x, y)
+ }
+ }
+ }
+
+ private fun dragAdjustedMove(x: Float, y: Float): Rect {
+ val absDiffX = abs(x - lastValidPoint.x)
+ val absDiffY = abs(y - lastValidPoint.y)
+ if (absDiffY < absDiffX) {
+ lastValidPoint.set(getScaledChangeForX(y), y)
+ return super.onDragPositioningMove(getScaledChangeForX(y), y)
+ }
+ lastValidPoint.set(x, getScaledChangeForY(x))
+ return super.onDragPositioningMove(x, getScaledChangeForY(x))
+ }
+
+ private fun dragAdjustedEnd(x: Float, y: Float): Rect {
+ val absDiffX = abs(x - lastValidPoint.x)
+ val absDiffY = abs(y - lastValidPoint.y)
+ if (absDiffY < absDiffX) {
+ return super.onDragPositioningEnd(getScaledChangeForX(y), y)
+ }
+ return super.onDragPositioningEnd(x, getScaledChangeForY(x))
+ }
+
+ /**
+ * Calculate the required change in the y dimension, given the change in the x dimension, to
+ * maintain the applications starting aspect ratio when resizing to a given x coordinate.
+ */
+ private fun getScaledChangeForY(x: Float): Float {
+ val changeXDimension = x - startingPoint.x
+ val changeYDimension = if (isTaskPortrait) {
+ changeXDimension * startingAspectRatio
+ } else {
+ changeXDimension / startingAspectRatio
+ }
+ if (originalCtrlType.isBottomRightOrTopLeftCorner()
+ || edgeResizeCtrlType.isBottomRightOrTopLeftCorner()) {
+ return startingPoint.y + changeYDimension
+ }
+ return startingPoint.y - changeYDimension
+ }
+
+ /**
+ * Calculate the required change in the x dimension, given the change in the y dimension, to
+ * maintain the applications starting aspect ratio when resizing to a given y coordinate.
+ */
+ private fun getScaledChangeForX(y: Float): Float {
+ val changeYDimension = y - startingPoint.y
+ val changeXDimension = if (isTaskPortrait) {
+ changeYDimension / startingAspectRatio
+ } else {
+ changeYDimension * startingAspectRatio
+ }
+ if (originalCtrlType.isBottomRightOrTopLeftCorner()
+ || edgeResizeCtrlType.isBottomRightOrTopLeftCorner()) {
+ return startingPoint.x + changeXDimension
+ }
+ return startingPoint.x - changeXDimension
+ }
+
+ /**
+ * If the action being triggered originated from the bottom right or top left corner of the
+ * window.
+ */
+ private fun @receiver:CtrlType Int.isBottomRightOrTopLeftCorner(): Boolean {
+ return this == CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT || this == CTRL_TYPE_TOP + CTRL_TYPE_LEFT
+ }
+
+ /**
+ * If the action being triggered is a resize action.
+ */
+ private fun @receiver:CtrlType Int.isResizing(): Boolean {
+ return (this and CTRL_TYPE_TOP) != 0 || (this and CTRL_TYPE_BOTTOM) != 0
+ || (this and CTRL_TYPE_LEFT) != 0 || (this and CTRL_TYPE_RIGHT) != 0
+ }
+
+ /**
+ * Whether the aspect ratio of the activity needs to be maintained during the current drag
+ * action. If the current action is not a resize (there is no bounds change) so the aspect ratio
+ * is already maintained and does not need handling here. If the activity is resizeable, it
+ * can handle aspect ratio changes itself so again we do not need to handle it here.
+ */
+ private fun requiresFixedAspectRatio(): Boolean {
+ return originalCtrlType.isResizing() && !windowDecoration.mTaskInfo.isResizeable
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 748046e..3d00a44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -71,6 +71,7 @@
private val splitScreenController: SplitScreenController,
private val shouldShowWindowingPill: Boolean,
private val shouldShowNewWindowButton: Boolean,
+ private val shouldShowManageWindowsButton: Boolean,
private val openInBrowserLink: Uri?,
private val captionWidth: Int,
private val captionHeight: Int,
@@ -119,6 +120,7 @@
onToFullscreenClickListener: () -> Unit,
onToSplitScreenClickListener: () -> Unit,
onNewWindowClickListener: () -> Unit,
+ onManageWindowsClickListener: () -> Unit,
openInBrowserClickListener: (Uri) -> Unit,
onCloseMenuClickListener: () -> Unit,
onOutsideTouchListener: () -> Unit,
@@ -133,6 +135,7 @@
onToFullscreenClickListener = onToFullscreenClickListener,
onToSplitScreenClickListener = onToSplitScreenClickListener,
onNewWindowClickListener = onNewWindowClickListener,
+ onManageWindowsClickListener = onManageWindowsClickListener,
openInBrowserClickListener = openInBrowserClickListener,
onCloseMenuClickListener = onCloseMenuClickListener,
onOutsideTouchListener = onOutsideTouchListener,
@@ -150,6 +153,7 @@
onToFullscreenClickListener: () -> Unit,
onToSplitScreenClickListener: () -> Unit,
onNewWindowClickListener: () -> Unit,
+ onManageWindowsClickListener: () -> Unit,
openInBrowserClickListener: (Uri) -> Unit,
onCloseMenuClickListener: () -> Unit,
onOutsideTouchListener: () -> Unit
@@ -160,13 +164,15 @@
captionHeight = captionHeight,
shouldShowWindowingPill = shouldShowWindowingPill,
shouldShowBrowserPill = shouldShowBrowserPill,
- shouldShowNewWindowButton = shouldShowNewWindowButton
+ shouldShowNewWindowButton = shouldShowNewWindowButton,
+ shouldShowManageWindowsButton = shouldShowManageWindowsButton
).apply {
bind(taskInfo, appIconBitmap, appName)
this.onToDesktopClickListener = onToDesktopClickListener
this.onToFullscreenClickListener = onToFullscreenClickListener
this.onToSplitScreenClickListener = onToSplitScreenClickListener
this.onNewWindowClickListener = onNewWindowClickListener
+ this.onManageWindowsClickListener = onManageWindowsClickListener
this.onOpenInBrowserClickListener = {
openInBrowserClickListener.invoke(openInBrowserLink!!)
}
@@ -372,7 +378,13 @@
R.dimen.desktop_mode_handle_menu_new_window_height
)
}
- if (!SHOULD_SHOW_SCREENSHOT_BUTTON && !shouldShowNewWindowButton) {
+ if (!shouldShowManageWindowsButton) {
+ menuHeight -= loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_manage_windows_height
+ )
+ }
+ if (!SHOULD_SHOW_SCREENSHOT_BUTTON && !shouldShowNewWindowButton
+ && !shouldShowManageWindowsButton) {
menuHeight -= pillTopMargin
}
if (!shouldShowBrowserPill) {
@@ -405,7 +417,8 @@
captionHeight: Int,
private val shouldShowWindowingPill: Boolean,
private val shouldShowBrowserPill: Boolean,
- private val shouldShowNewWindowButton: Boolean
+ private val shouldShowNewWindowButton: Boolean,
+ private val shouldShowManageWindowsButton: Boolean
) {
val rootView = LayoutInflater.from(context)
.inflate(R.layout.desktop_mode_window_decor_handle_menu, null /* root */) as View
@@ -430,6 +443,8 @@
private val moreActionsPill = rootView.requireViewById<View>(R.id.more_actions_pill)
private val screenshotBtn = moreActionsPill.requireViewById<Button>(R.id.screenshot_button)
private val newWindowBtn = moreActionsPill.requireViewById<Button>(R.id.new_window_button)
+ private val manageWindowBtn = moreActionsPill
+ .requireViewById<Button>(R.id.manage_windows_button)
// Open in Browser Pill.
private val openInBrowserPill = rootView.requireViewById<View>(R.id.open_in_browser_pill)
@@ -446,6 +461,7 @@
var onToFullscreenClickListener: (() -> Unit)? = null
var onToSplitScreenClickListener: (() -> Unit)? = null
var onNewWindowClickListener: (() -> Unit)? = null
+ var onManageWindowsClickListener: (() -> Unit)? = null
var onOpenInBrowserClickListener: (() -> Unit)? = null
var onCloseMenuClickListener: (() -> Unit)? = null
var onOutsideTouchListener: (() -> Unit)? = null
@@ -457,6 +473,7 @@
browserBtn.setOnClickListener { onOpenInBrowserClickListener?.invoke() }
collapseMenuButton.setOnClickListener { onCloseMenuClickListener?.invoke() }
newWindowBtn.setOnClickListener { onNewWindowClickListener?.invoke() }
+ manageWindowBtn.setOnClickListener { onManageWindowsClickListener?.invoke() }
rootView.setOnTouchListener { _, event ->
if (event.actionMasked == ACTION_OUTSIDE) {
@@ -587,6 +604,7 @@
private fun bindMoreActionsPill(style: MenuStyle) {
moreActionsPill.apply {
isGone = !shouldShowNewWindowButton && !SHOULD_SHOW_SCREENSHOT_BUTTON
+ && !shouldShowManageWindowsButton
}
screenshotBtn.apply {
isGone = !SHOULD_SHOW_SCREENSHOT_BUTTON
@@ -603,6 +621,13 @@
setTextColor(style.textColor)
compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
}
+ manageWindowBtn.apply {
+ isGone = !shouldShowManageWindowsButton
+ background.colorFilter =
+ BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY)
+ setTextColor(style.textColor)
+ compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
+ }
}
private fun bindOpenInBrowserPill(style: MenuStyle) {
@@ -643,6 +668,7 @@
splitScreenController: SplitScreenController,
shouldShowWindowingPill: Boolean,
shouldShowNewWindowButton: Boolean,
+ shouldShowManageWindowsButton: Boolean,
openInBrowserLink: Uri?,
captionWidth: Int,
captionHeight: Int,
@@ -661,6 +687,7 @@
splitScreenController: SplitScreenController,
shouldShowWindowingPill: Boolean,
shouldShowNewWindowButton: Boolean,
+ shouldShowManageWindowsButton: Boolean,
openInBrowserLink: Uri?,
captionWidth: Int,
captionHeight: Int,
@@ -675,6 +702,7 @@
splitScreenController,
shouldShowWindowingPill,
shouldShowNewWindowButton,
+ shouldShowManageWindowsButton,
openInBrowserLink,
captionWidth,
captionHeight,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 4af5b2c..3694845 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -62,6 +62,8 @@
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer;
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
import java.util.ArrayList;
import java.util.Arrays;
@@ -116,6 +118,7 @@
final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
final Supplier<WindowContainerTransaction> mWindowContainerTransactionSupplier;
final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
+ @NonNull private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
new DisplayController.OnDisplaysChangedListener() {
@Override
@@ -137,9 +140,7 @@
Context mDecorWindowContext;
SurfaceControl mDecorationContainerSurface;
- SurfaceControl mCaptionContainerSurface;
- private WindowlessWindowManager mCaptionWindowManager;
- private SurfaceControlViewHost mViewHost;
+ private WindowDecorViewHost mDecorViewHost;
private Configuration mWindowDecorConfig;
TaskDragResizer mTaskDragResizer;
boolean mIsCaptionVisible;
@@ -158,11 +159,13 @@
DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
RunningTaskInfo taskInfo,
- SurfaceControl taskSurface) {
+ SurfaceControl taskSurface,
+ @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
this(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
WindowContainerTransaction::new, SurfaceControl::new,
- new SurfaceControlViewHostFactory() {});
+ new SurfaceControlViewHostFactory() {},
+ windowDecorViewHostSupplier);
}
WindowDecoration(
@@ -176,7 +179,8 @@
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
Supplier<SurfaceControl> surfaceControlSupplier,
- SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
+ SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+ @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
mContext = context;
mUserContext = userContext;
mDisplayController = displayController;
@@ -187,6 +191,7 @@
mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
mWindowContainerTransactionSupplier = windowContainerTransactionSupplier;
mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
+ mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
final InsetsState insetsState = mDisplayController.getInsetsState(mTaskInfo.displayId);
mIsStatusBarVisible = insetsState != null
@@ -212,15 +217,7 @@
void relayout(RelayoutParams params, SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView,
RelayoutResult<T> outResult) {
- updateViewsAndSurfaces(params, startT, finishT, wct, rootView, outResult);
- if (outResult.mRootView != null) {
- updateViewHost(params, startT, outResult);
- }
- }
-
- protected void updateViewsAndSurfaces(RelayoutParams params,
- SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) {
+ Trace.beginSection("WindowDecoration#relayout");
outResult.reset();
if (params.mRunningTaskInfo != null) {
mTaskInfo = params.mRunningTaskInfo;
@@ -231,17 +228,21 @@
if (!mTaskInfo.isVisible) {
releaseViews(wct);
finishT.hide(mTaskSurface);
+ Trace.endSection(); // WindowDecoration#relayout
return;
}
-
+ Trace.beginSection("WindowDecoration#relayout-inflateIfNeeded");
inflateIfNeeded(params, wct, rootView, oldLayoutResId, outResult);
- if (outResult.mRootView == null) {
- // Didn't manage to create a root view, early out.
+ Trace.endSection();
+ final boolean hasCaptionView = outResult.mRootView != null;
+ if (!hasCaptionView) {
+ Trace.endSection(); // WindowDecoration#relayout
return;
}
- rootView = null; // Clear it just in case we use it accidentally
+ Trace.beginSection("WindowDecoration#relayout-updateCaptionVisibility");
updateCaptionVisibility(outResult.mRootView);
+ Trace.endSection();
final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
outResult.mWidth = taskBounds.width();
@@ -254,10 +255,23 @@
? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width();
outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
+ Trace.beginSection("WindowDecoration#relayout-acquire");
+ if (mDecorViewHost == null) {
+ mDecorViewHost = mWindowDecorViewHostSupplier.acquire(mDecorWindowContext, mDisplay);
+ }
+ Trace.endSection();
+
+ final SurfaceControl captionSurface = mDecorViewHost.getSurfaceControl();
+ Trace.beginSection("WindowDecoration#relayout-updateSurfacesAndInsets");
updateDecorationContainerSurface(startT, outResult);
- updateCaptionContainerSurface(startT, outResult);
+ updateCaptionContainerSurface(captionSurface, startT, outResult);
updateCaptionInsets(params, wct, outResult, taskBounds);
updateTaskSurface(params, startT, finishT, outResult);
+ Trace.endSection();
+
+ outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
+ updateViewHierarchy(params, outResult, startT);
+ Trace.endSection(); // WindowDecoration#relayout
}
private void inflateIfNeeded(RelayoutParams params, WindowContainerTransaction wct,
@@ -305,6 +319,32 @@
return (T) LayoutInflater.from(context).inflate(layoutResId, null);
}
+ private void updateViewHierarchy(@NonNull RelayoutParams params,
+ @NonNull RelayoutResult<T> outResult, @NonNull SurfaceControl.Transaction startT) {
+ Trace.beginSection("WindowDecoration#updateViewHierarchy");
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(
+ outResult.mCaptionWidth,
+ outResult.mCaptionHeight,
+ TYPE_APPLICATION,
+ FLAG_NOT_FOCUSABLE | FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSPARENT);
+ lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
+ lp.setTrustedOverlay();
+ lp.inputFeatures = params.mInputFeatures;
+ if (params.mAsyncViewHost) {
+ if (params.mApplyStartTransactionOnDraw) {
+ throw new IllegalArgumentException(
+ "We cannot both sync viewhost ondraw and delay viewhost creation.");
+ }
+ mDecorViewHost.updateViewAsync(outResult.mRootView, lp, mTaskInfo.getConfiguration());
+ } else {
+ mDecorViewHost.updateView(outResult.mRootView, lp, mTaskInfo.getConfiguration(),
+ params.mApplyStartTransactionOnDraw ? startT : null);
+ }
+ Trace.endSection();
+ }
+
private void updateDecorationContainerSurface(
SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
if (mDecorationContainerSurface == null) {
@@ -325,23 +365,14 @@
.show(mDecorationContainerSurface);
}
- private void updateCaptionContainerSurface(
+ private void updateCaptionContainerSurface(@NonNull SurfaceControl captionSurface,
SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
- if (mCaptionContainerSurface == null) {
- final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
- mCaptionContainerSurface = builder
- .setName("Caption container of Task=" + mTaskInfo.taskId)
- .setContainerLayer()
- .setParent(mDecorationContainerSurface)
- .setCallsite("WindowDecoration.updateCaptionContainerSurface")
- .build();
- }
-
- startT.setWindowCrop(mCaptionContainerSurface, outResult.mCaptionWidth,
+ startT.reparent(captionSurface, mDecorationContainerSurface)
+ .setWindowCrop(captionSurface, outResult.mCaptionWidth,
outResult.mCaptionHeight)
- .setPosition(mCaptionContainerSurface, outResult.mCaptionX, 0 /* y */)
- .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER)
- .show(mCaptionContainerSurface);
+ .setPosition(captionSurface, outResult.mCaptionX, 0 /* y */)
+ .setLayer(captionSurface, CAPTION_LAYER_Z_ORDER)
+ .show(captionSurface);
}
private void updateCaptionInsets(RelayoutParams params, WindowContainerTransaction wct,
@@ -435,64 +466,6 @@
}
}
- /**
- * Updates a {@link SurfaceControlViewHost} to connect the window decoration surfaces with our
- * View hierarchy.
- *
- * @param params parameters to use from the last relayout
- * @param onDrawTransaction a transaction to apply in sync with #onDraw
- * @param outResult results to use from the last relayout
- *
- */
- protected void updateViewHost(RelayoutParams params,
- SurfaceControl.Transaction onDrawTransaction, RelayoutResult<T> outResult) {
- Trace.beginSection("CaptionViewHostLayout");
- if (mCaptionWindowManager == null) {
- // Put caption under a container surface because ViewRootImpl sets the destination frame
- // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
- mCaptionWindowManager = new WindowlessWindowManager(
- mTaskInfo.getConfiguration(), mCaptionContainerSurface,
- null /* hostInputToken */);
- }
- mCaptionWindowManager.setConfiguration(mTaskInfo.getConfiguration());
- final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(
- outResult.mCaptionWidth,
- outResult.mCaptionHeight,
- TYPE_APPLICATION,
- FLAG_NOT_FOCUSABLE | FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSPARENT);
- lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
- lp.setTrustedOverlay();
- lp.inputFeatures = params.mInputFeatures;
- if (mViewHost == null) {
- Trace.beginSection("CaptionViewHostLayout-new");
- mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
- mCaptionWindowManager);
- if (params.mApplyStartTransactionOnDraw) {
- if (onDrawTransaction == null) {
- throw new IllegalArgumentException("Trying to sync a null Transaction");
- }
- mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
- }
- outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
- mViewHost.setView(outResult.mRootView, lp);
- Trace.endSection();
- } else {
- Trace.beginSection("CaptionViewHostLayout-relayout");
- if (params.mApplyStartTransactionOnDraw) {
- if (onDrawTransaction == null) {
- throw new IllegalArgumentException("Trying to sync a null Transaction");
- }
- mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
- }
- outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
- mViewHost.relayout(lp);
- Trace.endSection();
- }
- Trace.endSection(); // CaptionViewHostLayout
- }
-
private Rect calculateBoundingRect(@NonNull OccludingCaptionElement element,
int elementWidthPx, @NonNull Rect captionRect) {
switch (element.mAlignment) {
@@ -530,7 +503,14 @@
* Checks if task has entered/exited immersive mode and requires a change in caption visibility.
*/
private void updateCaptionVisibility(View rootView) {
- mIsCaptionVisible = mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded;
+ // Caption should always be visible in freeform mode. When not in freeform, align with the
+ // status bar except when showing over keyguard (where it should not shown).
+ // TODO(b/356405803): Investigate how it's possible for the status bar visibility to be
+ // false while a freeform window is open if the status bar is always forcibly-shown. It
+ // may be that the InsetsState (from which |mIsStatusBarVisible| is set) still contains
+ // an invisible insets source in immersive cases even if the status bar is shown?
+ mIsCaptionVisible = mTaskInfo.isFreeform()
+ || (mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded);
setCaptionVisibility(rootView, mIsCaptionVisible);
}
@@ -573,18 +553,11 @@
}
void releaseViews(WindowContainerTransaction wct) {
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
-
- mCaptionWindowManager = null;
-
final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
boolean released = false;
- if (mCaptionContainerSurface != null) {
- t.remove(mCaptionContainerSurface);
- mCaptionContainerSurface = null;
+ if (mDecorViewHost != null) {
+ mWindowDecorViewHostSupplier.release(mDecorViewHost, t);
+ mDecorViewHost = null;
released = true;
}
@@ -735,6 +708,7 @@
boolean mApplyStartTransactionOnDraw;
boolean mSetTaskPositionAndCrop;
+ boolean mAsyncViewHost;
void reset() {
mLayoutResId = Resources.ID_NULL;
@@ -751,6 +725,7 @@
mApplyStartTransactionOnDraw = false;
mSetTaskPositionAndCrop = false;
+ mAsyncViewHost = false;
mWindowDecorConfig = null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
new file mode 100644
index 0000000..139e679
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.content.res.Configuration
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import androidx.tracing.Trace
+import com.android.internal.annotations.VisibleForTesting
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+typealias SurfaceControlViewHostFactory =
+ (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
+
+/**
+ * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHost].
+ *
+ * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
+ * any attempts to do will throw, which means that once a [View] is added using [updateView] or
+ * [updateViewAsync], only its properties and binding may be changed, its children views may be
+ * added, removed or changed and its [WindowManager.LayoutParams] may be changed.
+ * It also supports asynchronously updating the view hierarchy using [updateViewAsync], in which
+ * case the update work will be posted on the [ShellMainThread] with no delay.
+ */
+class DefaultWindowDecorViewHost(
+ private val context: Context,
+ @ShellMainThread private val mainScope: CoroutineScope,
+ private val display: Display,
+ private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
+ SurfaceControlViewHost(c, d, wwm, s)
+ }
+) : WindowDecorViewHost {
+
+ private val rootSurface: SurfaceControl = SurfaceControl.Builder()
+ .setName("DefaultWindowDecorViewHost surface")
+ .setContainerLayer()
+ .setCallsite("DefaultWindowDecorViewHost#init")
+ .build()
+
+ private var wwm: WindowlessWindowManager? = null
+ @VisibleForTesting
+ var viewHost: SurfaceControlViewHost? = null
+ private var currentUpdateJob: Job? = null
+
+ override val surfaceControl: SurfaceControl
+ get() = rootSurface
+
+ override fun updateView(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration,
+ onDrawTransaction: SurfaceControl.Transaction?
+ ) {
+ Trace.beginSection("DefaultWindowDecorViewHost#updateView")
+ clearCurrentUpdateJob()
+ updateViewHost(view, attrs, configuration, onDrawTransaction)
+ Trace.endSection()
+ }
+
+ override fun updateViewAsync(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration
+ ) {
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewAsync")
+ clearCurrentUpdateJob()
+ currentUpdateJob = mainScope.launch {
+ updateViewHost(view, attrs, configuration, onDrawTransaction = null)
+ }
+ Trace.endSection()
+ }
+
+ override fun release(t: SurfaceControl.Transaction) {
+ clearCurrentUpdateJob()
+ viewHost?.release()
+ t.remove(rootSurface)
+ }
+
+ private fun updateViewHost(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration,
+ onDrawTransaction: SurfaceControl.Transaction?
+ ) {
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost")
+ if (wwm == null) {
+ wwm = WindowlessWindowManager(configuration, rootSurface, null)
+ }
+ requireWindowlessWindowManager().setConfiguration(configuration)
+ if (viewHost == null) {
+ viewHost = surfaceControlViewHostFactory.invoke(
+ context,
+ display,
+ requireWindowlessWindowManager(),
+ "DefaultWindowDecorViewHost#updateViewHost"
+ )
+ }
+ onDrawTransaction?.let {
+ requireViewHost().rootSurfaceControl.applyTransactionOnDraw(it)
+ }
+ if (requireViewHost().view == null) {
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-setView")
+ requireViewHost().setView(view, attrs)
+ Trace.endSection()
+ } else {
+ check(requireViewHost().view == view) { "Changing view is not allowed" }
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-relayout")
+ requireViewHost().relayout(attrs)
+ Trace.endSection()
+ }
+ Trace.endSection()
+ }
+
+ private fun clearCurrentUpdateJob() {
+ currentUpdateJob?.cancel()
+ currentUpdateJob = null
+ }
+
+ private fun requireWindowlessWindowManager(): WindowlessWindowManager {
+ return wwm ?: error("Expected non-null windowless window manager")
+ }
+
+ private fun requireViewHost(): SurfaceControlViewHost {
+ return viewHost ?: error("Expected non-null view host")
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..9997e8f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.view.Display
+import android.view.SurfaceControl
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * A supplier of [DefaultWindowDecorViewHost]s. It creates a new one every time one is requested.
+ */
+class DefaultWindowDecorViewHostSupplier(
+ @ShellMainThread private val mainScope: CoroutineScope,
+) : WindowDecorViewHostSupplier<DefaultWindowDecorViewHost> {
+
+ override fun acquire(context: Context, display: Display): DefaultWindowDecorViewHost {
+ return DefaultWindowDecorViewHost(context, mainScope, display)
+ }
+
+ override fun release(viewHost: DefaultWindowDecorViewHost, t: SurfaceControl.Transaction) {
+ viewHost.release(t)
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt
new file mode 100644
index 0000000..3fbaea8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.res.Configuration
+import android.view.SurfaceControl
+import android.view.View
+import android.view.WindowManager
+import com.android.wm.shell.windowdecor.WindowDecoration
+
+/**
+ * An interface for a utility that hosts a [WindowDecoration]'s [View] hierarchy under a
+ * [SurfaceControl].
+ */
+interface WindowDecorViewHost {
+ /** The surface where the underlying [View] hierarchy is being rendered. */
+ val surfaceControl: SurfaceControl
+
+ /** Synchronously update the view hierarchy of this view host. */
+ fun updateView(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration,
+ onDrawTransaction: SurfaceControl.Transaction?
+ )
+
+ /** Asynchronously update the view hierarchy of this view host. */
+ fun updateViewAsync(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration
+ )
+
+ /** Releases the underlying [View] hierarchy and removes the backing [SurfaceControl]. */
+ fun release(t: SurfaceControl.Transaction)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..0e23584
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.view.Display
+import android.view.SurfaceControl
+
+/**
+ * An interface for a supplier of [WindowDecorViewHost]s.
+ */
+interface WindowDecorViewHostSupplier<T : WindowDecorViewHost> {
+ /** Acquire a [WindowDecorViewHost]. */
+ fun acquire(context: Context, display: Display): T
+
+ /**
+ * Release a [WindowDecorViewHost] when it is no longer used.
+ *
+ * @param viewHost the [WindowDecorViewHost] to release
+ * @param t a transaction that may be used to remove any underlying backing [SurfaceControl]
+ * that are hosting this [WindowDecorViewHost]. The supplier is not expected to apply
+ * the transaction. It should be applied by the owner of this supplier.
+ */
+ fun release(viewHost: T, t: SurfaceControl.Transaction)
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 5b02837..497d0e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -18,6 +18,8 @@
import android.window.WindowContainerTransaction
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
@@ -448,6 +450,42 @@
)
}
+ @Test
+ fun startDragToDesktop_aborted_logsDragHoldCancelled() {
+ val transition = startDragToDesktopTransition(defaultHandler, createTask(), dragAnimator)
+
+ defaultHandler.onTransitionConsumed(transition, aborted = true, mock())
+
+ verify(mockInteractionJankMonitor).cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD))
+ verify(mockInteractionJankMonitor, times(0)).cancel(
+ eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE))
+ }
+
+ @Test
+ fun mergeEndDragToDesktop_aborted_logsDragReleaseCancelled() {
+ val task = createTask()
+ val startTransition = startDrag(defaultHandler, task)
+ val endTransition = mock<IBinder>()
+ defaultHandler.onTaskResizeAnimationListener = mock()
+ defaultHandler.mergeAnimation(
+ transition = endTransition,
+ info = createTransitionInfo(
+ type = TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP,
+ draggedTask = task
+ ),
+ t = mock<SurfaceControl.Transaction>(),
+ mergeTarget = startTransition,
+ finishCallback = mock<Transitions.TransitionFinishCallback>()
+ )
+
+ defaultHandler.onTransitionConsumed(endTransition, aborted = true, mock())
+
+ verify(mockInteractionJankMonitor)
+ .cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE))
+ verify(mockInteractionJankMonitor, times(0))
+ .cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD))
+ }
+
private fun startDrag(
handler: DragToDesktopTransitionHandler,
task: RunningTaskInfo = createTask(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
similarity index 92%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
index 645b296..46b60499 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
@@ -30,11 +30,11 @@
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -72,7 +72,7 @@
import com.android.internal.logging.InstanceId;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
+import com.android.wm.shell.draganddrop.SplitDragPolicy.Target;
import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.After;
@@ -92,7 +92,7 @@
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class DragAndDropPolicyTest extends ShellTestCase {
+public class SplitDragPolicyTest extends ShellTestCase {
@Mock
private Context mContext;
@@ -104,7 +104,7 @@
@Mock
private SplitScreenController mSplitScreenStarter;
@Mock
- private DragAndDropPolicy.Starter mFullscreenStarter;
+ private SplitDragPolicy.Starter mFullscreenStarter;
@Mock
private InstanceId mLoggerSessionId;
@@ -112,7 +112,7 @@
private DisplayLayout mLandscapeDisplayLayout;
private DisplayLayout mPortraitDisplayLayout;
private Insets mInsets;
- private DragAndDropPolicy mPolicy;
+ private SplitDragPolicy mPolicy;
private ClipData mActivityClipData;
private PendingIntent mLaunchableIntentPendingIntent;
@@ -150,7 +150,7 @@
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
+ mPolicy = spy(new SplitDragPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
mLaunchableIntentPendingIntent = mock(PendingIntent.class);
when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
@@ -289,7 +289,7 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
verify(mFullscreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_UNDEFINED), any(), any());
}
@@ -304,12 +304,12 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
reset(mSplitScreenStarter);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
}
@@ -324,12 +324,12 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
reset(mSplitScreenStarter);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
index 8c7b47e..e3798e9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
@@ -109,6 +109,7 @@
final Rect pipBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(50, 50, 150, 150);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
@@ -127,6 +128,7 @@
final Rect pipBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(100, 100, 150, 150);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
@@ -145,6 +147,7 @@
final Rect pipBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(50, 50, 150, 150);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
when(mMockPipBoundsState.isStashed()).thenReturn(true);
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
doAnswer(invocation -> {
@@ -164,6 +167,7 @@
final Rect pipBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(100, 100, 150, 150);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
when(mMockPipBoundsState.isStashed()).thenReturn(true);
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
doAnswer(invocation -> {
@@ -185,6 +189,7 @@
final Rect expected = new Rect(
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
arg0.set(DISPLAY_BOUNDS);
@@ -205,6 +210,7 @@
final Rect expected = new Rect(
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
arg0.set(DISPLAY_BOUNDS);
@@ -227,6 +233,7 @@
DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
arg0.set(DISPLAY_BOUNDS);
@@ -249,6 +256,7 @@
DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
arg0.set(DISPLAY_BOUNDS);
@@ -269,6 +277,7 @@
final Rect expected = new Rect(
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
when(mMockPipBoundsState.isStashed()).thenReturn(true);
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
@@ -289,6 +298,7 @@
final Rect expected = new Rect(
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
when(mMockPipBoundsState.isStashed()).thenReturn(true);
doAnswer(invocation -> {
Rect arg0 = invocation.getArgument(0);
@@ -301,4 +311,40 @@
assertEquals(expected, outBounds);
}
+
+ @Test
+ public void adjust_restoreBoundsPresent_appliesRestoreBounds() {
+ final Rect pipBounds = new Rect(0, 0, 100, 100);
+ final Rect restoreBounds = new Rect(50, 50, 150, 150);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(restoreBounds);
+ when(mMockPipBoundsState.hasUserMovedPip()).thenReturn(true);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+ assertEquals(restoreBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_restoreBoundsCleared_boundsUnchanged() {
+ final Rect pipBounds = new Rect(0, 0, 100, 100);
+ final Rect restoreBounds = new Rect(0, 0, 0, 0);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestoreBounds()).thenReturn(restoreBounds);
+ when(mMockPipBoundsState.hasUserMovedPip()).thenReturn(true);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+ assertEquals(pipBounds, outBounds);
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 6ddb678..f3944d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -256,7 +256,7 @@
when(mMockPipDisplayLayoutState.getDisplayLayout()).thenReturn(mMockDisplayLayout1);
when(mMockDisplayController.getDisplayLayout(displayId)).thenReturn(mMockDisplayLayout2);
- when(mMockPipTaskOrganizer.isInPip()).thenReturn(true);
+ when(mMockPipTransitionState.hasEnteredPip()).thenReturn(true);
mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
displayId, new Configuration());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index 2c805e8..a17d08d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -98,6 +98,7 @@
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier
import java.util.Optional
import java.util.function.Consumer
import java.util.function.Supplier
@@ -181,6 +182,7 @@
@Mock private lateinit var mockTaskPositionerFactory:
DesktopModeWindowDecorViewModel.TaskPositionerFactory
@Mock private lateinit var mockTaskPositioner: TaskPositioner
+ @Mock private lateinit var mockWindowDecorViewHostSupplier: WindowDecorViewHostSupplier<*>
private lateinit var spyContext: TestableContext
private val transactionFactory = Supplier<SurfaceControl.Transaction> {
@@ -230,6 +232,7 @@
mockGenericLinksParser,
mockAssistContentRequester,
mockMultiInstanceHelper,
+ mockWindowDecorViewHostSupplier,
mockDesktopModeWindowDecorFactory,
mockInputMonitorFactory,
transactionFactory,
@@ -1197,7 +1200,7 @@
whenever(
mockDesktopModeWindowDecorFactory.create(
any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(),
- any(), any(), any(), any())
+ any(), any(), any(), any(), any())
).thenReturn(decoration)
decoration.mTaskInfo = task
whenever(decoration.isFocused).thenReturn(task.isFocused)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index b9e542a0..1741fe4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -97,6 +97,8 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
@@ -162,6 +164,10 @@
@Mock
private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
@Mock
+ private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier;
+ @Mock
+ private WindowDecorViewHost mMockWindowDecorViewHost;
+ @Mock
private TypedArray mMockRoundedCornersRadiusArray;
@Mock
private TestTouchEventListener mMockTouchEventListener;
@@ -222,6 +228,8 @@
mTestableContext = new TestableContext(mContext);
mTestableContext.ensureTestableResources();
mContext.setMockPackageManager(mMockPackageManager);
+ when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any()))
+ .thenReturn(false);
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("applicationLabel");
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.applicationInfo = new ApplicationInfo();
@@ -229,10 +237,13 @@
final Display defaultDisplay = mock(Display.class);
doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
- when(mMockHandleMenuFactory.create(any(), any(), anyInt(), any(), any(),
- any(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()))
+ when(mMockHandleMenuFactory.create(any(), any(), anyInt(), any(), any(), any(),
+ anyBoolean(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()))
.thenReturn(mMockHandleMenu);
when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false);
+ when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay)))
+ .thenReturn(mMockWindowDecorViewHost);
+ when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
}
@After
@@ -504,6 +515,42 @@
}
@Test
+ public void updateRelayoutParams_handle_requestsAsyncViewHostRendering() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ // Make the task fullscreen so that its decoration is an App Handle.
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ // App Handles don't need to be rendered in sync with the task animation, per UX.
+ assertThat(relayoutParams.mAsyncViewHost).isTrue();
+ }
+
+ @Test
+ public void updateRelayoutParams_header_requestsSyncViewHostRendering() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ // Make the task freeform so that its decoration is an App Header.
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ // App Headers must be rendered in sync with the task animation, so it cannot be delayed.
+ assertThat(relayoutParams.mAsyncViewHost).isFalse();
+ }
+
+ @Test
public void relayout_fullscreenTask_appliesTransactionImmediately() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
@@ -526,74 +573,7 @@
spyWindowDecor.relayout(taskInfo);
verify(mMockTransaction, never()).apply();
- verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockTransaction);
- }
-
- @Test
- public void relayout_fullscreenTask_doesNotCreateViewHostImmediately() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
- spyWindowDecor.relayout(taskInfo);
-
- verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
- }
-
- @Test
- public void relayout_fullscreenTask_postsViewHostCreation() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
- ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
- spyWindowDecor.relayout(taskInfo);
-
- verify(mMockHandler).post(runnableArgument.capture());
- runnableArgument.getValue().run();
- verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
- }
-
- @Test
- public void relayout_freeformTask_createsViewHostImmediately() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
- // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
- taskInfo.isResizeable = false;
-
- spyWindowDecor.relayout(taskInfo);
-
- verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
- verify(mMockHandler, never()).post(any());
- }
-
- @Test
- public void relayout_removesExistingHandlerCallback() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
- spyWindowDecor.relayout(taskInfo);
- verify(mMockHandler).post(runnableArgument.capture());
-
- spyWindowDecor.relayout(taskInfo);
-
- verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
- }
-
- @Test
- public void close_removesExistingHandlerCallback() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
- spyWindowDecor.relayout(taskInfo);
- verify(mMockHandler).post(runnableArgument.capture());
-
- spyWindowDecor.close();
-
- verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
+ verify(mMockWindowDecorViewHost).updateView(any(), any(), any(), eq(mMockTransaction));
}
@Test
@@ -766,6 +746,7 @@
any(),
any(),
any(),
+ any(),
openInBrowserCaptor.capture(),
any(),
any()
@@ -793,6 +774,7 @@
any(),
any(),
any(),
+ any(),
openInBrowserCaptor.capture(),
any(),
any()
@@ -843,6 +825,7 @@
any(),
any(),
any(),
+ any(),
closeClickListener.capture(),
any()
);
@@ -854,8 +837,10 @@
}
private void verifyHandleMenuCreated(@Nullable Uri uri) {
+
verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(),
- any(), anyBoolean(), anyBoolean(), eq(uri), anyInt(), anyInt(), anyInt());
+ any(), anyBoolean(), anyBoolean(), anyBoolean(), eq(uri), anyInt(),
+ anyInt(), anyInt());
}
private void createMaximizeMenu(DesktopModeWindowDecoration decoration, MaximizeMenu menu) {
@@ -924,7 +909,8 @@
mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new,
mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory,
- maximizeMenuFactory, mMockHandleMenuFactory, mMockMultiInstanceHelper);
+ mMockWindowDecorViewHostSupplier, maximizeMenuFactory, mMockHandleMenuFactory,
+ mMockMultiInstanceHelper);
windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener,
mMockTouchEventListener, mMockTouchEventListener);
windowDecor.setExclusionRegionListener(mMockExclusionRegionListener);
@@ -953,7 +939,7 @@
}
private void createHandleMenu(@NonNull DesktopModeWindowDecoration decor) {
- decor.createHandleMenu();
+ decor.createHandleMenu(false);
// Call DesktopModeWindowDecoration#onAssistContentReceived because decor waits to receive
// {@link AssistContent} before creating the menu
decor.onAssistContentReceived(mAssistContent);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
index 100abbb..a845231 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
@@ -236,11 +236,11 @@
val handleMenu = HandleMenu(mockDesktopWindowDecoration,
WindowManagerWrapper(mockWindowManager),
layoutId, appIcon, appName, splitScreenController, shouldShowWindowingPill = true,
- shouldShowNewWindowButton = true,
+ shouldShowNewWindowButton = true, shouldShowManageWindowsButton = false,
null /* openInBrowserLink */, captionWidth = HANDLE_WIDTH, captionHeight = 50,
captionX = captionX
)
- handleMenu.show(mock(), mock(), mock(), mock(), mock(), mock(), mock())
+ handleMenu.show(mock(), mock(), mock(), mock(), mock(), mock(), mock(), mock())
return handleMenu
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 6154391c..7252b32 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -85,6 +85,8 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.tests.R;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
import org.junit.Before;
import org.junit.Rule;
@@ -128,6 +130,10 @@
@Mock
private SurfaceControlViewHost mMockSurfaceControlViewHost;
@Mock
+ private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier;
+ @Mock
+ private WindowDecorViewHost mMockWindowDecorViewHost;
+ @Mock
private AttachedSurfaceControl mMockRootSurfaceControl;
@Mock
private TestView mMockView;
@@ -167,6 +173,9 @@
when(mMockSurfaceControlViewHost.getRootSurfaceControl())
.thenReturn(mMockRootSurfaceControl);
when(mMockView.findViewById(anyInt())).thenReturn(mMockView);
+ when(mMockWindowDecorViewHostSupplier.acquire(any(), any()))
+ .thenReturn(mMockWindowDecorViewHost);
+ when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
// Add status bar inset so that WindowDecoration does not think task is in immersive mode
mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, statusBars()).setVisible(true);
@@ -230,10 +239,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
.setDisplayId(Display.DEFAULT_DISPLAY)
@@ -254,18 +259,18 @@
verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true);
verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 300, 100);
- verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
- verify(captionContainerSurfaceBuilder).setContainerLayer();
+ final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl();
+ verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface);
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
- verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
-
- verify(mMockSurfaceControlViewHost)
- .setView(same(mMockView),
- argThat(lp -> lp.height == 64
- && lp.width == 300
- && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0));
+ verify(mMockWindowDecorViewHost).updateView(
+ same(mMockView),
+ argThat(lp -> lp.height == 64
+ && lp.width == 300
+ && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0),
+ eq(taskInfo.configuration),
+ eq(null) /* onDrawTransaction */);
verify(mMockView).setTaskFocusState(true);
verify(mMockWindowContainerTransaction).addInsetsSource(
eq(taskInfo.token),
@@ -296,10 +301,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -322,7 +323,7 @@
windowDecor.relayout(taskInfo);
- verify(mMockSurfaceControlViewHost, never()).release();
+ verify(mMockWindowDecorViewHost, never()).release(any());
verify(t, never()).apply();
verify(mMockWindowContainerTransaction, never())
.removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
@@ -332,9 +333,8 @@
taskInfo.isVisible = false;
windowDecor.relayout(taskInfo);
- final InOrder releaseOrder = inOrder(t2, mMockSurfaceControlViewHost);
- releaseOrder.verify(mMockSurfaceControlViewHost).release();
- releaseOrder.verify(t2).remove(captionContainerSurface);
+ final InOrder releaseOrder = inOrder(t2, mMockWindowDecorViewHostSupplier);
+ releaseOrder.verify(mMockWindowDecorViewHostSupplier).release(mMockWindowDecorViewHost, t2);
releaseOrder.verify(t2).remove(decorContainerSurface);
releaseOrder.verify(t2).apply();
// Expect to remove two insets sources, the caption insets and the mandatory gesture insets.
@@ -382,8 +382,8 @@
verify(mMockDisplayController).removeDisplayWindowListener(same(listener));
assertThat(mRelayoutResult.mRootView).isSameInstanceAs(mMockView);
- verify(mMockSurfaceControlViewHostFactory).create(any(), eq(mockDisplay), any());
- verify(mMockSurfaceControlViewHost).setView(same(mMockView), any());
+ verify(mMockWindowDecorViewHostSupplier).acquire(any(), eq(mockDisplay));
+ verify(mMockWindowDecorViewHost).updateView(same(mMockView), any(), any(), any());
}
@Test
@@ -396,10 +396,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -436,8 +432,7 @@
windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId);
verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
- verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
- .create(any(), eq(defaultDisplay), any());
+ verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
}
@Test
@@ -450,10 +445,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -473,8 +464,8 @@
windowDecor.relayout(taskInfo);
- verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
- verify(captionContainerSurfaceBuilder).setContainerLayer();
+ final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl();
+ verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface);
// Width of the captionContainerSurface should match the width of TASK_BOUNDS
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
@@ -490,10 +481,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -511,9 +498,11 @@
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
- windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */);
+ mRelayoutParams.mApplyStartTransactionOnDraw = true;
+ windowDecor.relayout(taskInfo);
- verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+ verify(mMockWindowDecorViewHost).updateView(any(), any(), any(),
+ eq(mMockSurfaceControlStartT));
}
@Test
@@ -867,42 +856,58 @@
}
@Test
- public void updateViewHost_applyTransactionOnDrawIsTrue_surfaceControlIsUpdated() {
+ public void relayout_applyTransactionOnDrawIsTrue_updatesViewWithDrawTransaction() {
final TestWindowDecoration windowDecor = createWindowDecoration(
- new TestRunningTaskInfoBuilder().build());
+ new TestRunningTaskInfoBuilder()
+ .setVisible(true)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build());
mRelayoutParams.mApplyStartTransactionOnDraw = true;
mRelayoutResult.mRootView = mMockView;
- windowDecor.updateViewHost(mRelayoutParams, mMockSurfaceControlStartT, mRelayoutResult);
+ windowDecor.relayout(windowDecor.mTaskInfo);
- verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+ verify(mMockWindowDecorViewHost)
+ .updateView(eq(mRelayoutResult.mRootView), any(),
+ eq(windowDecor.mTaskInfo.configuration), eq(mMockSurfaceControlStartT));
}
@Test
- public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsTrue_throwsException() {
+ public void relayout_applyTransactionOnDrawIsTrue_asyncViewHostRendering_throwsException() {
final TestWindowDecoration windowDecor = createWindowDecoration(
- new TestRunningTaskInfoBuilder().build());
+ new TestRunningTaskInfoBuilder()
+ .setVisible(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .build());
mRelayoutParams.mApplyStartTransactionOnDraw = true;
+ mRelayoutParams.mAsyncViewHost = true;
mRelayoutResult.mRootView = mMockView;
assertThrows(IllegalArgumentException.class,
- () -> windowDecor.updateViewHost(
- mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult));
+ () -> windowDecor.relayout(windowDecor.mTaskInfo));
}
@Test
- public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsFalse_doesNotThrow() {
+ public void relayout_asyncViewHostRendering() {
final TestWindowDecoration windowDecor = createWindowDecoration(
- new TestRunningTaskInfoBuilder().build());
- mRelayoutParams.mApplyStartTransactionOnDraw = false;
+ new TestRunningTaskInfoBuilder()
+ .setVisible(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .build());
+ mRelayoutParams.mAsyncViewHost = true;
mRelayoutResult.mRootView = mMockView;
- windowDecor.updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult);
+ windowDecor.relayout(windowDecor.mTaskInfo);
+
+ verify(mMockWindowDecorViewHost)
+ .updateViewAsync(eq(mRelayoutResult.mRootView), any(),
+ eq(windowDecor.mTaskInfo.configuration));
}
@Test
- public void onStatusBarVisibilityChange_shownToHidden_hidesCaption() {
+ public void onStatusBarVisibilityChange_fullscreen_shownToHidden_hidesCaption() {
final ActivityManager.RunningTaskInfo task = createTaskInfo();
+ task.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
when(mMockDisplayController.getInsetsState(task.displayId))
.thenReturn(createInsetsState(statusBars(), true /* visible */));
final TestWindowDecoration decor = createWindowDecoration(task);
@@ -915,8 +920,9 @@
}
@Test
- public void onStatusBarVisibilityChange_hiddenToShown_showsCaption() {
+ public void onStatusBarVisibilityChange_fullscreen_hiddenToShown_showsCaption() {
final ActivityManager.RunningTaskInfo task = createTaskInfo();
+ task.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
when(mMockDisplayController.getInsetsState(task.displayId))
.thenReturn(createInsetsState(statusBars(), false /* visible */));
final TestWindowDecoration decor = createWindowDecoration(task);
@@ -929,6 +935,21 @@
}
@Test
+ public void onStatusBarVisibilityChange_freeform_shownToHidden_keepsCaption() {
+ final ActivityManager.RunningTaskInfo task = createTaskInfo();
+ task.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ when(mMockDisplayController.getInsetsState(task.displayId))
+ .thenReturn(createInsetsState(statusBars(), true /* visible */));
+ final TestWindowDecoration decor = createWindowDecoration(task);
+ decor.relayout(task);
+ assertTrue(decor.mIsCaptionVisible);
+
+ decor.onInsetsStateChanged(createInsetsState(statusBars(), false /* visible */));
+
+ assertTrue(decor.mIsCaptionVisible);
+ }
+
+ @Test
public void onKeyguardStateChange_hiddenToShownAndOccluding_hidesCaption() {
final ActivityManager.RunningTaskInfo task = createTaskInfo();
when(mMockDisplayController.getInsetsState(task.displayId))
@@ -980,7 +1001,8 @@
new MockObjectSupplier<>(mMockSurfaceControlTransactions,
() -> mock(SurfaceControl.Transaction.class)),
() -> mMockWindowContainerTransaction, () -> mMockTaskSurface,
- mMockSurfaceControlViewHostFactory);
+ mMockSurfaceControlViewHostFactory,
+ mMockWindowDecorViewHostSupplier);
}
private class MockObjectSupplier<T> implements Supplier<T> {
@@ -1020,16 +1042,20 @@
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
Supplier<SurfaceControl> surfaceControlSupplier,
- SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
+ SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+ @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
windowContainerTransactionSupplier, surfaceControlSupplier,
- surfaceControlViewHostFactory);
+ surfaceControlViewHostFactory, windowDecorViewHostSupplier);
}
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
- relayout(taskInfo, false /* applyStartTransactionOnDraw */);
+ mRelayoutParams.mRunningTaskInfo = taskInfo;
+ mRelayoutParams.mLayoutResId = R.layout.caption_layout;
+ relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
+ mMockWindowContainerTransaction, mMockView, mRelayoutResult);
}
@Override
@@ -1050,15 +1076,6 @@
return super.inflateLayout(context, layoutResId);
}
- void relayout(ActivityManager.RunningTaskInfo taskInfo,
- boolean applyStartTransactionOnDraw) {
- mRelayoutParams.mRunningTaskInfo = taskInfo;
- mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
- mRelayoutParams.mLayoutResId = R.layout.caption_layout;
- relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
- mMockWindowContainerTransaction, mMockView, mRelayoutResult);
- }
-
private AdditionalViewContainer addTestViewContainer() {
final Resources resources = mDecorWindowContext.getResources();
final int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
new file mode 100644
index 0000000..1b2ce9e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+
+/**
+ * Tests for [DefaultWindowDecorViewHost].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:DefaultWindowDecorViewHostTest
+ */
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DefaultWindowDecorViewHostTest : ShellTestCase() {
+
+ @Test
+ fun updateView_layoutInViewHost() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val view = View(context)
+
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+ }
+
+ @Test
+ fun updateView_alreadyLaidOut_relayouts() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val view = View(context)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ val otherParams = WindowManager.LayoutParams(200, 200)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = otherParams,
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+ assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+ .isEqualTo(otherParams.width)
+ }
+
+ @Test
+ fun updateView_replacingView_throws() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val view = View(context)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ val otherView = View(context)
+ assertThrows(Exception::class.java) {
+ windowDecorViewHost.updateView(
+ view = otherView,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun updateView_clearsPendingAsyncJob() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val asyncView = View(context)
+ val syncView = View(context)
+ val asyncAttrs = WindowManager.LayoutParams(100, 100)
+ val syncAttrs = WindowManager.LayoutParams(200, 200)
+
+ windowDecorViewHost.updateViewAsync(
+ view = asyncView,
+ attrs = asyncAttrs,
+ configuration = context.resources.configuration,
+ )
+
+ // No view host yet, since the coroutine hasn't run.
+ assertThat(windowDecorViewHost.viewHost).isNull()
+
+ windowDecorViewHost.updateView(
+ view = syncView,
+ attrs = syncAttrs,
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ // Would run coroutine if it hadn't been cancelled.
+ advanceUntilIdle()
+
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+ // View host view/attrs should match the ones from the sync call, plus, since the
+ // sync/async were made with different views, if the job hadn't been cancelled there
+ // would've been an exception thrown as replacing views isn't allowed.
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(syncView)
+ assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+ .isEqualTo(syncAttrs.width)
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun updateViewAsync() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val view = View(context)
+ val attrs = WindowManager.LayoutParams(100, 100)
+
+ windowDecorViewHost.updateViewAsync(
+ view = view,
+ attrs = attrs,
+ configuration = context.resources.configuration,
+ )
+
+ assertThat(windowDecorViewHost.viewHost).isNull()
+
+ advanceUntilIdle()
+
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun updateViewAsync_clearsPendingAsyncJob() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+
+ val view = View(context)
+ windowDecorViewHost.updateViewAsync(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ )
+ val otherView = View(context)
+ windowDecorViewHost.updateViewAsync(
+ view = otherView,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ )
+
+ advanceUntilIdle()
+
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(otherView)
+ }
+
+ @Test
+ fun release() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+
+ val view = View(context)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ val t = mock(SurfaceControl.Transaction::class.java)
+ windowDecorViewHost.release(t)
+
+ verify(windowDecorViewHost.viewHost!!).release()
+ verify(t).remove(windowDecorViewHost.surfaceControl)
+ }
+
+ private fun CoroutineScope.createDefaultViewHost() = DefaultWindowDecorViewHost(
+ context = context,
+ mainScope = this,
+ display = context.display,
+ surfaceControlViewHostFactory = { c, d, wwm, s ->
+ spy(SurfaceControlViewHost(c, d, wwm, s))
+ }
+ )
+}
\ No newline at end of file
diff --git a/libs/appfunctions/OWNERS b/libs/appfunctions/OWNERS
new file mode 100644
index 0000000..c093675
--- /dev/null
+++ b/libs/appfunctions/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include /core/java/android/app/appfunctions/OWNERS
diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp
index 5a45ad9..8deac61 100644
--- a/libs/hwui/SkiaInterpolator.cpp
+++ b/libs/hwui/SkiaInterpolator.cpp
@@ -47,6 +47,8 @@
return static_cast<Dot14>(x * Dot14_ONE);
}
+using MSec = uint32_t; // millisecond duration
+
static float SkUnitCubicInterp(float value, float bx, float by, float cx, float cy) {
// pin to the unit-square, and convert to 2.14
Dot14 x = pin_and_convert(value);
@@ -120,7 +122,7 @@
Totaling fElemCount+2 entries per keyframe
*/
-bool SkiaInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
+bool SkiaInterpolatorBase::getDuration(MSec* startTime, MSec* endTime) const {
if (fFrameCount == 0) {
return false;
}
@@ -134,7 +136,7 @@
return true;
}
-float SkiaInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime,
+float SkiaInterpolatorBase::ComputeRelativeT(MSec time, MSec prevTime, MSec nextTime,
const float blend[4]) {
LOG_FATAL_IF(time < prevTime || time > nextTime);
@@ -144,7 +146,7 @@
// Returns the index of where the item is or the bit not of the index
// where the item should go in order to keep arr sorted in ascending order.
-int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, SkMSec target) {
+int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, MSec target) {
if (count <= 0) {
return ~0;
}
@@ -154,7 +156,7 @@
while (lo < hi) {
int mid = (hi + lo) / 2;
- SkMSec elem = arr[mid].fTime;
+ MSec elem = arr[mid].fTime;
if (elem == target) {
return mid;
} else if (elem < target) {
@@ -171,21 +173,21 @@
return ~(lo + 1);
}
-SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T, int* indexPtr,
+SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(MSec time, float* T, int* indexPtr,
bool* exactPtr) const {
LOG_FATAL_IF(fFrameCount <= 0);
Result result = kNormal_Result;
if (fRepeat != 1.0f) {
- SkMSec startTime = 0, endTime = 0; // initialize to avoid warning
+ MSec startTime = 0, endTime = 0; // initialize to avoid warning
this->getDuration(&startTime, &endTime);
- SkMSec totalTime = endTime - startTime;
- SkMSec offsetTime = time - startTime;
+ MSec totalTime = endTime - startTime;
+ MSec offsetTime = time - startTime;
endTime = SkScalarFloorToInt(fRepeat * totalTime);
if (offsetTime >= endTime) {
float fraction = SkScalarFraction(fRepeat);
offsetTime = fraction == 0 && fRepeat > 0
? totalTime
- : (SkMSec)SkScalarFloorToInt(fraction * totalTime);
+ : (MSec)SkScalarFloorToInt(fraction * totalTime);
result = kFreezeEnd_Result;
} else {
int mirror = fFlags & kMirror;
@@ -217,11 +219,11 @@
}
LOG_FATAL_IF(index >= fFrameCount);
const SkTimeCode* nextTime = &fTimes[index];
- SkMSec nextT = nextTime[0].fTime;
+ MSec nextT = nextTime[0].fTime;
if (exact) {
*T = 0;
} else {
- SkMSec prevT = nextTime[-1].fTime;
+ MSec prevT = nextTime[-1].fTime;
*T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
}
*indexPtr = index;
@@ -251,7 +253,7 @@
static const float gIdentityBlend[4] = {0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f};
-bool SkiaInterpolator::setKeyFrame(int index, SkMSec time, const float values[],
+bool SkiaInterpolator::setKeyFrame(int index, MSec time, const float values[],
const float blend[4]) {
LOG_FATAL_IF(values == nullptr);
@@ -272,7 +274,7 @@
return success;
}
-SkiaInterpolator::Result SkiaInterpolator::timeToValues(SkMSec time, float values[]) const {
+SkiaInterpolator::Result SkiaInterpolator::timeToValues(MSec time, float values[]) const {
float T;
int index;
bool exact;
diff --git a/libs/hwui/apex/android_bitmap.cpp b/libs/hwui/apex/android_bitmap.cpp
index c80a9b4..000f109 100644
--- a/libs/hwui/apex/android_bitmap.cpp
+++ b/libs/hwui/apex/android_bitmap.cpp
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-#include <log/log.h>
-
-#include "android/graphics/bitmap.h"
-#include "TypeCast.h"
-#include "GraphicsJNI.h"
-
+#include <Gainmap.h>
#include <GraphicsJNI.h>
-#include <hwui/Bitmap.h>
#include <SkBitmap.h>
#include <SkColorSpace.h>
#include <SkImageInfo.h>
#include <SkRefCnt.h>
#include <SkStream.h>
+#include <hwui/Bitmap.h>
+#include <log/log.h>
#include <utils/Color.h>
+#include "GraphicsJNI.h"
+#include "TypeCast.h"
+#include "android/graphics/bitmap.h"
+
using namespace android;
ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) {
@@ -215,6 +215,14 @@
int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat inFormat, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc fn) {
+ return ABitmap_compressWithGainmap(info, dataSpace, pixels, nullptr, -1.f, inFormat, quality,
+ userContext, fn);
+}
+
+int ABitmap_compressWithGainmap(const AndroidBitmapInfo* info, ADataSpace dataSpace,
+ const void* pixels, const void* gainmapPixels, float hdrSdrRatio,
+ AndroidBitmapCompressFormat inFormat, int32_t quality,
+ void* userContext, AndroidBitmap_CompressWriteFunc fn) {
Bitmap::JavaCompressFormat format;
switch (inFormat) {
case ANDROID_BITMAP_COMPRESS_FORMAT_JPEG:
@@ -275,7 +283,7 @@
// besides ADATASPACE_UNKNOWN as an error?
cs = nullptr;
} else {
- cs = uirenderer::DataSpaceToColorSpace((android_dataspace) dataSpace);
+ cs = uirenderer::DataSpaceToColorSpace((android_dataspace)dataSpace);
// DataSpaceToColorSpace treats UNKNOWN as SRGB, but compress forces the
// client to specify SRGB if that is what they want.
if (!cs || dataSpace == ADATASPACE_UNKNOWN) {
@@ -292,16 +300,70 @@
auto imageInfo =
SkImageInfo::Make(info->width, info->height, colorType, alphaType, std::move(cs));
- SkBitmap bitmap;
- // We are not going to modify the pixels, but installPixels expects them to
- // not be const, since for all it knows we might want to draw to the SkBitmap.
- if (!bitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) {
- return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+
+ // Validate the image info
+ {
+ SkBitmap tempBitmap;
+ if (!tempBitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) {
+ return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+ }
+ }
+
+ SkPixelRef pixelRef =
+ SkPixelRef(info->width, info->height, const_cast<void*>(pixels), info->stride);
+
+ auto bitmap = Bitmap::createFrom(imageInfo, pixelRef);
+
+ if (gainmapPixels) {
+ auto gainmap = sp<uirenderer::Gainmap>::make();
+ gainmap->info.fGainmapRatioMin = {
+ 1.f,
+ 1.f,
+ 1.f,
+ 1.f,
+ };
+ gainmap->info.fGainmapRatioMax = {
+ hdrSdrRatio,
+ hdrSdrRatio,
+ hdrSdrRatio,
+ 1.f,
+ };
+ gainmap->info.fGainmapGamma = {
+ 1.f,
+ 1.f,
+ 1.f,
+ 1.f,
+ };
+
+ static constexpr auto kDefaultEpsilon = 1.f / 64.f;
+ gainmap->info.fEpsilonSdr = {
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ 1.f,
+ };
+ gainmap->info.fEpsilonHdr = {
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ 1.f,
+ };
+ gainmap->info.fDisplayRatioSdr = 1.f;
+ gainmap->info.fDisplayRatioHdr = hdrSdrRatio;
+
+ SkPixelRef gainmapPixelRef = SkPixelRef(info->width, info->height,
+ const_cast<void*>(gainmapPixels), info->stride);
+ auto gainmapBitmap = Bitmap::createFrom(imageInfo, gainmapPixelRef);
+ gainmap->bitmap = std::move(gainmapBitmap);
+ bitmap->setGainmap(std::move(gainmap));
}
CompressWriter stream(userContext, fn);
- return Bitmap::compress(bitmap, format, quality, &stream) ? ANDROID_BITMAP_RESULT_SUCCESS
- : ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+
+ return bitmap->compress(format, quality, &stream)
+
+ ? ANDROID_BITMAP_RESULT_SUCCESS
+ : ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmapHandle) {
diff --git a/libs/hwui/apex/include/android/graphics/bitmap.h b/libs/hwui/apex/include/android/graphics/bitmap.h
index 8c4b439d..6f65e9e 100644
--- a/libs/hwui/apex/include/android/graphics/bitmap.h
+++ b/libs/hwui/apex/include/android/graphics/bitmap.h
@@ -65,6 +65,13 @@
ANDROID_API int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat format, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc);
+// If gainmapPixels is null, then no gainmap is encoded, and hdrSdrRatio is
+// unused
+ANDROID_API int ABitmap_compressWithGainmap(const AndroidBitmapInfo* info, ADataSpace dataSpace,
+ const void* pixels, const void* gainmapPixels,
+ float hdrSdrRatio, AndroidBitmapCompressFormat format,
+ int32_t quality, void* userContext,
+ AndroidBitmap_CompressWriteFunc);
/**
* Retrieve the native object associated with a HARDWARE Bitmap.
*
diff --git a/libs/hwui/jni/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp
index ae6ac4c..6c82aa1 100644
--- a/libs/hwui/jni/GIFMovie.cpp
+++ b/libs/hwui/jni/GIFMovie.cpp
@@ -30,7 +30,7 @@
protected:
virtual bool onGetInfo(Info*);
- virtual bool onSetTime(SkMSec);
+ virtual bool onSetTime(Movie::MSec);
virtual bool onGetBitmap(SkBitmap*);
private:
@@ -72,7 +72,7 @@
DGifCloseFile(fGIF, nullptr);
}
-static SkMSec savedimage_duration(const SavedImage* image)
+static Movie::MSec savedimage_duration(const SavedImage* image)
{
for (int j = 0; j < image->ExtensionBlockCount; j++)
{
@@ -91,7 +91,7 @@
if (nullptr == fGIF)
return false;
- SkMSec dur = 0;
+ Movie::MSec dur = 0;
for (int i = 0; i < fGIF->ImageCount; i++)
dur += savedimage_duration(&fGIF->SavedImages[i]);
@@ -102,12 +102,12 @@
return true;
}
-bool GIFMovie::onSetTime(SkMSec time)
+bool GIFMovie::onSetTime(Movie::MSec time)
{
if (nullptr == fGIF)
return false;
- SkMSec dur = 0;
+ Movie::MSec dur = 0;
for (int i = 0; i < fGIF->ImageCount; i++)
{
dur += savedimage_duration(&fGIF->SavedImages[i]);
diff --git a/libs/hwui/jni/Movie.h b/libs/hwui/jni/Movie.h
index 02113dd..d633d93 100644
--- a/libs/hwui/jni/Movie.h
+++ b/libs/hwui/jni/Movie.h
@@ -19,6 +19,8 @@
class Movie : public SkRefCnt {
public:
+ using MSec = uint32_t; // millisecond duration
+
/** Try to create a movie from the stream. If the stream format is not
supported, return NULL.
*/
@@ -36,7 +38,7 @@
*/
static Movie* DecodeMemory(const void* data, size_t length);
- SkMSec duration();
+ MSec duration();
int width();
int height();
int isOpaque();
@@ -46,21 +48,21 @@
bitmap/frame from the previous state (i.e. true means you need to
redraw).
*/
- bool setTime(SkMSec);
+ bool setTime(MSec);
// return the right bitmap for the current time code
const SkBitmap& bitmap();
protected:
struct Info {
- SkMSec fDuration;
+ MSec fDuration;
int fWidth;
int fHeight;
bool fIsOpaque;
};
virtual bool onGetInfo(Info*) = 0;
- virtual bool onSetTime(SkMSec) = 0;
+ virtual bool onSetTime(MSec) = 0;
virtual bool onGetBitmap(SkBitmap*) = 0;
// visible for subclasses
@@ -68,7 +70,7 @@
private:
Info fInfo;
- SkMSec fCurrTime;
+ MSec fCurrTime;
SkBitmap fBitmap;
bool fNeedBitmap;
diff --git a/libs/hwui/jni/MovieImpl.cpp b/libs/hwui/jni/MovieImpl.cpp
index abb75fa..a31a15f 100644
--- a/libs/hwui/jni/MovieImpl.cpp
+++ b/libs/hwui/jni/MovieImpl.cpp
@@ -11,7 +11,7 @@
// We should never see this in normal operation since our time values are
// 0-based. So we use it as a sentinel.
-#define UNINITIALIZED_MSEC ((SkMSec)-1)
+#define UNINITIALIZED_MSEC ((Movie::MSec)-1)
Movie::Movie()
{
@@ -26,7 +26,7 @@
memset(&fInfo, 0, sizeof(fInfo)); // failure
}
-SkMSec Movie::duration()
+Movie::MSec Movie::duration()
{
this->ensureInfo();
return fInfo.fDuration;
@@ -50,9 +50,9 @@
return fInfo.fIsOpaque;
}
-bool Movie::setTime(SkMSec time)
+bool Movie::setTime(Movie::MSec time)
{
- SkMSec dur = this->duration();
+ Movie::MSec dur = this->duration();
if (time > dur)
time = dur;
diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt
index d03ceb4..2414299 100644
--- a/libs/hwui/libhwui.map.txt
+++ b/libs/hwui/libhwui.map.txt
@@ -13,6 +13,7 @@
ABitmapConfig_getFormatFromConfig;
ABitmapConfig_getConfigFromFormat;
ABitmap_compress;
+ ABitmap_compressWithGainmap;
ABitmap_getHardwareBuffer;
ACanvas_isSupportedPixelFormat;
ACanvas_getNativeHandleFromJava;
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index bbd91fc..dcf5c5b 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -116,4 +116,7 @@
description: "Flag for enabling NI SUPL message injection by carrier config"
bug: "242105192"
is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS
index 880ec8f..2b72744 100644
--- a/media/java/android/media/projection/OWNERS
+++ b/media/java/android/media/projection/OWNERS
@@ -1,7 +1,7 @@
# Bug component: 1345447
-michaelwr@google.com
-santoscordon@google.com
-chaviw@google.com
-nmusgrave@google.com
+marvinramin@google.com
dakinola@google.com
+vaniadesmonda@google.com
+caen@google.com
+santoscordon@google.com
\ No newline at end of file
diff --git a/media/tests/LoudnessCodecApiTest/Android.bp b/media/tests/LoudnessCodecApiTest/Android.bp
index 5ca0fc9..5d1153d 100644
--- a/media/tests/LoudnessCodecApiTest/Android.bp
+++ b/media/tests/LoudnessCodecApiTest/Android.bp
@@ -25,3 +25,10 @@
resource_dirs: ["res"],
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "LoudnessCodecApiTest_Presubmit",
+ base: "LoudnessCodecApiTest",
+ test_suites: ["device-tests"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 346c87d..25c063d6 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -367,6 +367,7 @@
APerformanceHint_sendHint;
APerformanceHint_getThreadIds;
APerformanceHint_createSessionInternal;
+ APerformanceHint_setUseFMQForTesting;
extern "C++" {
ASurfaceControl_registerSurfaceStatsListener*;
ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index e91c7a9..095d7d1 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -16,10 +16,14 @@
#define LOG_TAG "perf_hint"
+#include <aidl/android/hardware/power/ChannelConfig.h>
+#include <aidl/android/hardware/power/ChannelMessage.h>
+#include <aidl/android/hardware/power/SessionConfig.h>
#include <aidl/android/hardware/power/SessionHint.h>
#include <aidl/android/hardware/power/SessionMode.h>
#include <aidl/android/hardware/power/SessionTag.h>
#include <aidl/android/hardware/power/WorkDuration.h>
+#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
#include <aidl/android/os/IHintManager.h>
#include <aidl/android/os/IHintSession.h>
#include <android-base/stringprintf.h>
@@ -28,6 +32,8 @@
#include <android/binder_status.h>
#include <android/performance_hint.h>
#include <android/trace.h>
+#include <android_os.h>
+#include <fmq/AidlMessageQueue.h>
#include <inttypes.h>
#include <performance_hint_private.h>
#include <utils/SystemClock.h>
@@ -45,6 +51,10 @@
// Namespace for AIDL types coming from the PowerHAL
namespace hal = aidl::android::hardware::power;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
+using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
+using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
using android::base::StringPrintf;
struct APerformanceHintSession;
@@ -54,18 +64,60 @@
// Shared lock for the whole PerformanceHintManager and sessions
static std::mutex sHintMutex = std::mutex{};
+class FMQWrapper {
+public:
+ bool isActive();
+ bool isSupported();
+ bool startChannel(IHintManager* manager);
+ void stopChannel(IHintManager* manager);
+ // Number of elements the FMQ can hold
+ bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
+ hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
+ bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
+ int64_t targetDurationNanos) REQUIRES(sHintMutex);
+ bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex);
+ bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
+ REQUIRES(sHintMutex);
+ void setToken(ndk::SpAIBinder& token);
+ void attemptWake();
+ void setUnsupported();
+
+private:
+ template <HalChannelMessageContents::Tag T, bool urgent = false,
+ class C = HalChannelMessageContents::_at<T>>
+ bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1)
+ REQUIRES(sHintMutex);
+ template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
+ void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex);
+
+ bool isActiveLocked() REQUIRES(sHintMutex);
+ bool updatePersistentTransaction() REQUIRES(sHintMutex);
+ std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
+ std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
+ // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
+ android::hardware::EventFlag* mEventFlag = nullptr;
+ int32_t mWriteMask;
+ ndk::SpAIBinder mToken = nullptr;
+ // Used to track if operating on the fmq consistently fails
+ bool mCorrupted = false;
+ // Used to keep a persistent transaction open with FMQ to reduce latency a bit
+ size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
+ bool mHalSupported = true;
+ HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
+};
struct APerformanceHintManager {
public:
static APerformanceHintManager* getInstance();
- APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
+ APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
APerformanceHintManager() = delete;
- ~APerformanceHintManager() = default;
+ ~APerformanceHintManager();
APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos,
hal::SessionTag tag = hal::SessionTag::APP);
int64_t getPreferredRateNanos() const;
+ FMQWrapper& getFMQWrapper();
private:
// Necessary to create an empty binder object
@@ -83,6 +135,7 @@
std::shared_ptr<IHintManager> mHintManager;
ndk::SpAIBinder mToken;
const int64_t mPreferredRateNanos;
+ FMQWrapper mFMQWrapper;
};
struct APerformanceHintSession {
@@ -121,40 +174,57 @@
std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
// Cached samples
std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
- std::string mSessionName GUARDED_BY(sHintMutex);
+ std::string mSessionName;
static int64_t sIDCounter GUARDED_BY(sHintMutex);
// The most recent set of thread IDs
std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
// Tracing helpers
void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
- void tracePowerEfficient(bool powerEfficient) REQUIRES(sHintMutex);
- void traceActualDuration(int64_t actualDuration) REQUIRES(sHintMutex);
- void traceBatchSize(size_t batchSize) REQUIRES(sHintMutex);
- void traceTargetDuration(int64_t targetDuration) REQUIRES(sHintMutex);
+ void tracePowerEfficient(bool powerEfficient);
+ void traceActualDuration(int64_t actualDuration);
+ void traceBatchSize(size_t batchSize);
+ void traceTargetDuration(int64_t targetDuration);
};
static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
-static APerformanceHintManager* gHintManagerForTesting = nullptr;
+static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
+
+static std::optional<bool> gForceFMQEnabled = std::nullopt;
+
// Start above the int32 range so we don't collide with config sessions
int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
+static FMQWrapper& getFMQ() {
+ return APerformanceHintManager::getInstance()->getFMQWrapper();
+}
+
// ===================================== APerformanceHintManager implementation
-APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
+APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
int64_t preferredRateNanos)
: mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
static AIBinder_Class* tokenBinderClass =
AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
tokenStubOnTransact);
mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
+ if (mFMQWrapper.isSupported()) {
+ mFMQWrapper.setToken(mToken);
+ mFMQWrapper.startChannel(mHintManager.get());
+ }
+}
+
+APerformanceHintManager::~APerformanceHintManager() {
+ mFMQWrapper.stopChannel(mHintManager.get());
}
APerformanceHintManager* APerformanceHintManager::getInstance() {
- if (gHintManagerForTesting) return gHintManagerForTesting;
+ if (gHintManagerForTesting) {
+ return gHintManagerForTesting.get();
+ }
if (gIHintManagerForTesting) {
- APerformanceHintManager* manager = create(*gIHintManagerForTesting);
- gIHintManagerForTesting = nullptr;
- return manager;
+ gHintManagerForTesting =
+ std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
+ return gHintManagerForTesting.get();
}
static APerformanceHintManager* instance = create(nullptr);
return instance;
@@ -178,7 +248,7 @@
if (preferredRateNanos <= 0) {
preferredRateNanos = -1L;
}
- return new APerformanceHintManager(std::move(manager), preferredRateNanos);
+ return new APerformanceHintManager(manager, preferredRateNanos);
}
APerformanceHintSession* APerformanceHintManager::createSession(
@@ -187,15 +257,20 @@
std::vector<int32_t> tids(threadIds, threadIds + size);
std::shared_ptr<IHintSession> session;
ndk::ScopedAStatus ret;
- std::optional<hal::SessionConfig> sessionConfig;
+ hal::SessionConfig sessionConfig{.id = -1};
ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
tag, &sessionConfig, &session);
if (!ret.isOk() || !session) {
+ ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
return nullptr;
}
auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
- initialTargetWorkDurationNanos, sessionConfig);
+ initialTargetWorkDurationNanos,
+ sessionConfig.id == -1
+ ? std::nullopt
+ : std::make_optional<hal::SessionConfig>(
+ std::move(sessionConfig)));
std::scoped_lock lock(sHintMutex);
out->traceThreads(tids);
out->traceTargetDuration(initialTargetWorkDurationNanos);
@@ -207,8 +282,15 @@
return mPreferredRateNanos;
}
+FMQWrapper& APerformanceHintManager::getFMQWrapper() {
+ return mFMQWrapper;
+}
+
// ===================================== APerformanceHintSession implementation
+constexpr int kNumEnums =
+ ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
+
APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
std::shared_ptr<IHintSession> session,
int64_t preferredRateNanos,
@@ -220,14 +302,11 @@
mTargetDurationNanos(targetDurationNanos),
mFirstTargetMetTimestamp(0),
mLastTargetMetTimestamp(0),
+ mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
mSessionConfig(sessionConfig) {
if (sessionConfig->id > INT32_MAX) {
ALOGE("Session ID too large, must fit 32-bit integer");
}
- std::scoped_lock lock(sHintMutex);
- constexpr int numEnums =
- ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
- mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
}
@@ -244,19 +323,18 @@
ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
return EINVAL;
}
- {
- std::scoped_lock lock(sHintMutex);
- if (mTargetDurationNanos == targetDurationNanos) {
- return 0;
+ std::scoped_lock lock(sHintMutex);
+ if (mTargetDurationNanos == targetDurationNanos) {
+ return 0;
+ }
+ if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
+ ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
+ ret.getMessage());
+ return EPIPE;
}
}
- ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
- if (!ret.isOk()) {
- ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
- ret.getMessage());
- return EPIPE;
- }
- std::scoped_lock lock(sHintMutex);
mTargetDurationNanos = targetDurationNanos;
/**
* Most of the workload is target_duration dependent, so now clear the cached samples
@@ -292,11 +370,13 @@
return 0;
}
- ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
+ if (!getFMQ().sendHint(mSessionConfig, hint)) {
+ ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
- if (!ret.isOk()) {
- ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
- return EPIPE;
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
+ return EPIPE;
+ }
}
mLastHintSentTimestamp[hint] = now;
return 0;
@@ -369,10 +449,10 @@
int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
int64_t actualTotalDurationNanos = workDuration->durationNanos;
+ traceActualDuration(workDuration->durationNanos);
int64_t now = uptimeNanos();
workDuration->timeStampNanos = now;
std::scoped_lock lock(sHintMutex);
- traceActualDuration(workDuration->durationNanos);
mActualWorkDurations.push_back(std::move(*workDuration));
if (actualTotalDurationNanos >= mTargetDurationNanos) {
@@ -396,20 +476,177 @@
mLastTargetMetTimestamp = now;
}
- ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
- if (!ret.isOk()) {
- ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
- ret.getMessage());
- mFirstTargetMetTimestamp = 0;
- mLastTargetMetTimestamp = 0;
- traceBatchSize(mActualWorkDurations.size());
- return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
+ if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
+ mActualWorkDurations.size())) {
+ ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
+ ret.getMessage());
+ mFirstTargetMetTimestamp = 0;
+ mLastTargetMetTimestamp = 0;
+ traceBatchSize(mActualWorkDurations.size());
+ return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
+ }
}
+
mActualWorkDurations.clear();
traceBatchSize(0);
return 0;
}
+
+// ===================================== FMQ wrapper implementation
+
+bool FMQWrapper::isActive() {
+ std::scoped_lock lock{sHintMutex};
+ return isActiveLocked();
+}
+
+bool FMQWrapper::isActiveLocked() {
+ return mQueue != nullptr;
+}
+
+void FMQWrapper::setUnsupported() {
+ mHalSupported = false;
+}
+
+bool FMQWrapper::isSupported() {
+ if (!mHalSupported) {
+ return false;
+ }
+ // Used for testing
+ if (gForceFMQEnabled.has_value()) {
+ return *gForceFMQEnabled;
+ }
+ return android::os::adpf_use_fmq_channel_fixed();
+}
+
+bool FMQWrapper::startChannel(IHintManager* manager) {
+ if (isSupported() && !isActive()) {
+ std::optional<hal::ChannelConfig> config;
+ auto ret = manager->getSessionChannel(mToken, &config);
+ if (ret.isOk() && config.has_value()) {
+ std::scoped_lock lock{sHintMutex};
+ mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
+ if (config->eventFlagDescriptor.has_value()) {
+ mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
+ android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
+ &mEventFlag);
+ mWriteMask = config->writeFlagBitmask;
+ }
+ updatePersistentTransaction();
+ } else if (ret.isOk() && !config.has_value()) {
+ ALOGV("FMQ channel enabled but unsupported.");
+ setUnsupported();
+ } else {
+ ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
+ }
+ }
+ return isActive();
+}
+
+void FMQWrapper::stopChannel(IHintManager* manager) {
+ {
+ std::scoped_lock lock{sHintMutex};
+ if (!isActiveLocked()) {
+ return;
+ }
+ mFlagQueue = nullptr;
+ mQueue = nullptr;
+ }
+ manager->closeSessionChannel();
+}
+
+template <HalChannelMessageContents::Tag T, class C>
+void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) {
+ new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{
+ .sessionID = static_cast<int32_t>(config.id),
+ .timeStampNanos = ::android::uptimeNanos(),
+ .data = HalChannelMessageContents::make<T, C>(std::move(*message)),
+ };
+}
+
+template <>
+void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
+ hal::SessionConfig& config,
+ size_t count) {
+ for (size_t i = 0; i < count; ++i) {
+ hal::WorkDuration& message = messages[i];
+ new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
+ .sessionID = static_cast<int32_t>(config.id),
+ .timeStampNanos =
+ (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos,
+ .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
+ hal::WorkDurationFixedV1>({
+ .durationNanos = message.cpuDurationNanos,
+ .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
+ .cpuDurationNanos = message.cpuDurationNanos,
+ .gpuDurationNanos = message.gpuDurationNanos,
+ }),
+ };
+ }
+}
+
+template <HalChannelMessageContents::Tag T, bool urgent, class C>
+bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) {
+ if (!isActiveLocked() || !config.has_value() || mCorrupted) {
+ return false;
+ }
+ // If we didn't reserve enough space, try re-creating the transaction
+ if (count > mAvailableSlots) {
+ if (!updatePersistentTransaction()) {
+ return false;
+ }
+ // If we actually don't have enough space, give up
+ if (count > mAvailableSlots) {
+ return false;
+ }
+ }
+ writeBuffer<T, C>(message, *config, count);
+ mQueue->commitWrite(count);
+ mEventFlag->wake(mWriteMask);
+ // Re-create the persistent transaction after writing
+ updatePersistentTransaction();
+ return true;
+}
+
+void FMQWrapper::setToken(ndk::SpAIBinder& token) {
+ mToken = token;
+}
+
+bool FMQWrapper::updatePersistentTransaction() {
+ mAvailableSlots = mQueue->availableToWrite();
+ if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
+ ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
+ mCorrupted = true;
+ return false;
+ }
+ return true;
+}
+
+bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
+ hal::WorkDuration* durations, size_t count) {
+ return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
+}
+
+bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
+ int64_t targetDurationNanos) {
+ return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
+}
+
+bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) {
+ return sendMessages<HalChannelMessageContents::hint>(config,
+ reinterpret_cast<hal::SessionHint*>(
+ &hint));
+}
+
+bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
+ bool enabled) {
+ hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
+ .enabled = enabled};
+ return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
+}
+
// ===================================== Tracing helpers
void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
@@ -585,7 +822,12 @@
}
void APerformanceHint_setIHintManagerForTesting(void* iManager) {
- delete gHintManagerForTesting;
- gHintManagerForTesting = nullptr;
+ if (iManager == nullptr) {
+ gHintManagerForTesting = nullptr;
+ }
gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
}
+
+void APerformanceHint_setUseFMQForTesting(bool enabled) {
+ gForceFMQEnabled = enabled;
+}
diff --git a/native/android/tests/performance_hint/Android.bp b/native/android/tests/performance_hint/Android.bp
index 608d5d8..f6f1da1 100644
--- a/native/android/tests/performance_hint/Android.bp
+++ b/native/android/tests/performance_hint/Android.bp
@@ -36,10 +36,13 @@
srcs: ["PerformanceHintNativeTest.cpp"],
shared_libs: [
+ "android.hardware.common.fmq-V1-ndk",
"libandroid",
- "liblog",
"libbinder",
"libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
"libpowermanager",
"libutils",
],
@@ -56,8 +59,8 @@
],
cflags: [
- "-Werror",
"-Wall",
+ "-Werror",
],
header_libs: [
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index d19fa98..9de3a6f 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -24,6 +24,7 @@
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <android/performance_hint.h>
+#include <fmq/AidlMessageQueue.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <performance_hint_private.h>
@@ -31,11 +32,16 @@
#include <memory>
#include <vector>
+using namespace std::chrono_literals;
namespace hal = aidl::android::hardware::power;
using aidl::android::os::IHintManager;
using aidl::android::os::IHintSession;
using ndk::ScopedAStatus;
using ndk::SpAIBinder;
+using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
+
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
using namespace android;
using namespace testing;
@@ -44,7 +50,7 @@
public:
MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
(const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos,
- hal::SessionTag tag, std::optional<hal::SessionConfig>* config,
+ hal::SessionTag tag, hal::SessionConfig* config,
std::shared_ptr<IHintSession>* _aidl_return),
(override));
MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
@@ -56,7 +62,9 @@
(const std::shared_ptr<IHintSession>& hintSession, ::std::vector<int32_t>* tids),
(override));
MOCK_METHOD(ScopedAStatus, getSessionChannel,
- (const ::ndk::SpAIBinder& in_token, hal::ChannelConfig* _aidl_return), (override));
+ (const ::ndk::SpAIBinder& in_token,
+ std::optional<hal::ChannelConfig>* _aidl_return),
+ (override));
MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
MOCK_METHOD(SpAIBinder, asBinder, (), (override));
MOCK_METHOD(bool, isRemote, (), (override));
@@ -92,10 +100,12 @@
}
APerformanceHintManager* createManager() {
+ APerformanceHint_setUseFMQForTesting(mUsingFMQ);
ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
.WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); }));
return APerformanceHint_getManager();
}
+
APerformanceHintSession* createSession(APerformanceHintManager* manager,
int64_t targetDuration = 56789L, bool isHwui = false) {
mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
@@ -106,8 +116,7 @@
ON_CALL(*mMockIHintManager,
createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _))
- .WillByDefault(DoAll(SetArgPointee<4>(std::make_optional<hal::SessionConfig>(
- {.id = sessionId})),
+ .WillByDefault(DoAll(SetArgPointee<4>(hal::SessionConfig({.id = sessionId})),
SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)),
[] { return ScopedAStatus::ok(); }));
@@ -133,8 +142,47 @@
return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
}
+ void setFMQEnabled(bool enabled) {
+ mUsingFMQ = enabled;
+ if (enabled) {
+ mMockFMQ = std::make_shared<
+ AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>>(kMockQueueSize,
+ true);
+ mMockFlagQueue =
+ std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(1, true);
+ hardware::EventFlag::createEventFlag(mMockFlagQueue->getEventFlagWord(), &mEventFlag);
+
+ ON_CALL(*mMockIHintManager, getSessionChannel(_, _))
+ .WillByDefault([&](ndk::SpAIBinder, std::optional<hal::ChannelConfig>* config) {
+ config->emplace(
+ hal::ChannelConfig{.channelDescriptor = mMockFMQ->dupeDesc(),
+ .eventFlagDescriptor =
+ mMockFlagQueue->dupeDesc(),
+ .readFlagBitmask =
+ static_cast<int32_t>(mReadBits),
+ .writeFlagBitmask =
+ static_cast<int32_t>(mWriteBits)});
+ return ::ndk::ScopedAStatus::ok();
+ });
+ }
+ }
+ uint32_t mReadBits = 0x00000001;
+ uint32_t mWriteBits = 0x00000002;
std::shared_ptr<NiceMock<MockIHintManager>> mMockIHintManager = nullptr;
std::shared_ptr<NiceMock<MockIHintSession>> mMockSession = nullptr;
+ std::shared_ptr<AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>> mMockFMQ;
+ std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mMockFlagQueue;
+ hardware::EventFlag* mEventFlag;
+ int kMockQueueSize = 20;
+ bool mUsingFMQ = false;
+
+ template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
+ void expectToReadFromFmq(C expected) {
+ hal::ChannelMessage readData;
+ mMockFMQ->readBlocking(&readData, 1, mReadBits, mWriteBits, 1000000000, mEventFlag);
+ C got = static_cast<C>(readData.data.get<T>());
+ ASSERT_EQ(got, expected);
+ }
};
bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) {
@@ -306,7 +354,7 @@
actualWorkDurations.push_back(pair.duration);
EXPECT_CALL(*mMockSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
- .Times(Exactly(1));
+ .Times(Exactly(pair.expectedResult == OK));
result = APerformanceHint_reportActualWorkDuration2(session,
reinterpret_cast<AWorkDuration*>(
&pair.duration));
@@ -327,3 +375,48 @@
AWorkDuration_setActualGpuDurationNanos(aWorkDuration, 8);
AWorkDuration_release(aWorkDuration);
}
+
+TEST_F(PerformanceHintTest, TestCreateUsingFMQ) {
+ setFMQEnabled(true);
+ APerformanceHintManager* manager = createManager();
+ APerformanceHintSession* session = createSession(manager);
+ ASSERT_TRUE(session);
+}
+
+TEST_F(PerformanceHintTest, TestUpdateTargetWorkDurationUsingFMQ) {
+ setFMQEnabled(true);
+ APerformanceHintManager* manager = createManager();
+ APerformanceHintSession* session = createSession(manager);
+ APerformanceHint_updateTargetWorkDuration(session, 456);
+ expectToReadFromFmq<HalChannelMessageContents::Tag::targetDuration>(456);
+}
+
+TEST_F(PerformanceHintTest, TestSendHintUsingFMQ) {
+ setFMQEnabled(true);
+ APerformanceHintManager* manager = createManager();
+ APerformanceHintSession* session = createSession(manager);
+ APerformanceHint_sendHint(session, SessionHint::CPU_LOAD_UP);
+ expectToReadFromFmq<HalChannelMessageContents::Tag::hint>(hal::SessionHint::CPU_LOAD_UP);
+}
+
+TEST_F(PerformanceHintTest, TestReportActualUsingFMQ) {
+ setFMQEnabled(true);
+ APerformanceHintManager* manager = createManager();
+ APerformanceHintSession* session = createSession(manager);
+ hal::WorkDuration duration{.timeStampNanos = 3,
+ .durationNanos = 999999,
+ .workPeriodStartTimestampNanos = 1,
+ .cpuDurationNanos = 999999,
+ .gpuDurationNanos = 999999};
+
+ hal::WorkDurationFixedV1 durationExpected{
+ .durationNanos = duration.durationNanos,
+ .workPeriodStartTimestampNanos = duration.workPeriodStartTimestampNanos,
+ .cpuDurationNanos = duration.cpuDurationNanos,
+ .gpuDurationNanos = duration.gpuDurationNanos,
+ };
+
+ APerformanceHint_reportActualWorkDuration2(session,
+ reinterpret_cast<AWorkDuration*>(&duration));
+ expectToReadFromFmq<HalChannelMessageContents::Tag::workDuration>(durationExpected);
+}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b997c35..0cb85d8 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -42,8 +42,6 @@
"SettingsLibIllustrationPreference",
"SettingsLibLayoutPreference",
"SettingsLibMainSwitchPreference",
- "SettingsLibMetadata",
- "SettingsLibPreference",
"SettingsLibProfileSelector",
"SettingsLibProgressBar",
"SettingsLibRestrictedLockUtils",
diff --git a/packages/SettingsLib/Graph/Android.bp b/packages/SettingsLib/Graph/Android.bp
index e2ed1e4..163b689 100644
--- a/packages/SettingsLib/Graph/Android.bp
+++ b/packages/SettingsLib/Graph/Android.bp
@@ -4,7 +4,7 @@
filegroup {
name: "SettingsLibGraph-srcs",
- srcs: ["src/**/*"],
+ srcs: ["src/**/*.kt"],
}
android_library {
@@ -14,8 +14,24 @@
],
srcs: [":SettingsLibGraph-srcs"],
static_libs: [
+ "SettingsLibGraph-proto-lite",
+ "SettingsLibIpc",
+ "SettingsLibMetadata",
+ "SettingsLibPreference",
"androidx.annotation_annotation",
+ "androidx.fragment_fragment",
"androidx.preference_preference",
],
kotlincflags: ["-Xjvm-default=all"],
}
+
+java_library {
+ name: "SettingsLibGraph-proto-lite",
+ srcs: ["graph.proto"],
+ proto: {
+ type: "lite",
+ canonical_path_from_root: false,
+ },
+ sdk_version: "core_current",
+ static_libs: ["libprotobuf-java-lite"],
+}
diff --git a/packages/SettingsLib/Graph/graph.proto b/packages/SettingsLib/Graph/graph.proto
new file mode 100644
index 0000000..e93d756
--- /dev/null
+++ b/packages/SettingsLib/Graph/graph.proto
@@ -0,0 +1,156 @@
+syntax = "proto3";
+
+package com.android.settingslib.graph;
+
+option java_package = "com.android.settingslib.graph.proto";
+option java_multiple_files = true;
+
+// Proto represents preference graph.
+message PreferenceGraphProto {
+ // Preference screens appear in the graph.
+ // Key: preference key of the PreferenceScreen. Value: PreferenceScreen.
+ map<string, PreferenceScreenProto> screens = 1;
+ // Roots of the graph.
+ // Each element is a preference key of the PreferenceScreen.
+ repeated string roots = 2;
+ // Activities appear in the graph.
+ // Key: activity class. Value: preference key of associated PreferenceScreen.
+ map<string, string> activity_screens = 3;
+}
+
+// Proto of PreferenceScreen.
+message PreferenceScreenProto {
+ // Intent to show the PreferenceScreen.
+ optional IntentProto intent = 1;
+ // Root of the PreferenceScreen hierarchy.
+ optional PreferenceGroupProto root = 2;
+ // If the preference screen provides complete hierarchy by source code.
+ optional bool complete_hierarchy = 3;
+}
+
+// Proto of PreferenceGroup.
+message PreferenceGroupProto {
+ // Self information of PreferenceGroup.
+ optional PreferenceProto preference = 1;
+ // A list of children.
+ repeated PreferenceOrGroupProto preferences = 2;
+}
+
+// Proto represents either PreferenceProto or PreferenceGroupProto.
+message PreferenceOrGroupProto {
+ oneof kind {
+ // It is a Preference.
+ PreferenceProto preference = 1;
+ // It is a PreferenceGroup.
+ PreferenceGroupProto group = 2;
+ }
+}
+
+// Proto of Preference.
+message PreferenceProto {
+ // Key of the preference.
+ optional string key = 1;
+ // Title of the preference.
+ optional TextProto title = 2;
+ // Summary of the preference.
+ optional TextProto summary = 3;
+ // Icon of the preference.
+ optional int32 icon = 4;
+ // Additional keywords for indexing.
+ optional int32 keywords = 5;
+ // Extras of the preference.
+ optional BundleProto extras = 6;
+ // Whether the preference is indexable.
+ optional bool indexable = 7;
+ // Whether the preference is enabled.
+ optional bool enabled = 8;
+ // Whether the preference is available/visible.
+ optional bool available = 9;
+ // Whether the preference is persistent.
+ optional bool persistent = 10;
+ // Whether the preference is restricted by managed configurations.
+ optional bool restricted = 11;
+ // Target of the preference action.
+ optional ActionTarget action_target = 12;
+ // Preference value (if present, it means `persistent` is true).
+ optional PreferenceValueProto value = 13;
+
+ // Target of an Intent
+ message ActionTarget {
+ oneof kind {
+ // Resolved key of the preference screen located in current app.
+ // This is resolved from android:fragment or activity of current app.
+ string key = 1;
+ // Unresolvable Intent that is either an unrecognized activity of current
+ // app or activity belongs to other app.
+ IntentProto intent = 2;
+ }
+ }
+}
+
+// Proto of string or string resource id.
+message TextProto {
+ oneof text {
+ int32 resource_id = 1;
+ string string = 2;
+ }
+}
+
+// Proto of preference value.
+message PreferenceValueProto {
+ oneof value {
+ bool boolean_value = 1;
+ }
+}
+
+// Proto of android.content.Intent
+message IntentProto {
+ // The action of the Intent.
+ optional string action = 1;
+
+ // The data attribute of the Intent, expressed as a URI.
+ optional string data = 2;
+
+ // The package attribute of the Intent, which may be set to force the
+ // detection of a particular application package that can handle the event.
+ optional string pkg = 3;
+
+ // The component attribute of the Intent, which may be set to force the
+ // detection of a particular component (app). If present, this must be a
+ // package name followed by a '/' and then followed by the class name.
+ optional string component = 4;
+
+ // Flags controlling how intent is handled. The value must be bitwise OR of
+ // intent flag constants defined by Android.
+ // http://developer.android.com/reference/android/content/Intent.html#setFlags(int)
+ optional int32 flags = 5;
+
+ // Extended data from the intent.
+ optional BundleProto extras = 6;
+
+ // The MIME type of the Intent (e.g. "text/plain").
+ //
+ // For more information, see
+ // https://developer.android.com/reference/android/content/Intent#setType(java.lang.String).
+ optional string mime_type = 7;
+}
+
+// Proto of android.os.Bundle
+message BundleProto {
+ // Bundle data.
+ map<string, BundleValue> values = 1;
+
+ message BundleValue {
+ // Bundle data value for the associated key name.
+ // Can be extended to support other types of bundled data.
+ oneof value {
+ string string_value = 1;
+ bytes bytes_value = 2;
+ int32 int_value = 3;
+ int64 long_value = 4;
+ bool boolean_value = 5;
+ double double_value = 6;
+ BundleProto bundle_value = 7;
+ }
+ }
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
new file mode 100644
index 0000000..04c2968
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import android.app.Application
+import android.os.Bundle
+import com.android.settingslib.graph.proto.PreferenceGraphProto
+import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.MessageCodec
+import java.util.Locale
+
+/** API to get preference graph. */
+abstract class GetPreferenceGraphApiHandler(private val activityClasses: Set<String>) :
+ ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
+
+ override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
+ get() = GetPreferenceGraphRequestCodec
+
+ override val responseCodec: MessageCodec<PreferenceGraphProto>
+ get() = PreferenceGraphProtoCodec
+
+ override suspend fun invoke(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: GetPreferenceGraphRequest,
+ ): PreferenceGraphProto {
+ val builderRequest =
+ if (request.activityClasses.isEmpty()) {
+ GetPreferenceGraphRequest(activityClasses, request.visitedScreens, request.locale)
+ } else {
+ request
+ }
+ return PreferenceGraphBuilder.of(application, builderRequest).build()
+ }
+}
+
+/**
+ * Request of [GetPreferenceGraphApiHandler].
+ *
+ * @param activityClasses activities of the preference graph
+ * @param visitedScreens keys of the visited preference screen
+ * @param locale locale of the preference graph
+ */
+data class GetPreferenceGraphRequest
+@JvmOverloads
+constructor(
+ val activityClasses: Set<String> = setOf(),
+ val visitedScreens: Set<String> = setOf(),
+ val locale: Locale? = null,
+ val includeValue: Boolean = true,
+)
+
+object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> {
+ override fun encode(data: GetPreferenceGraphRequest): Bundle =
+ Bundle(3).apply {
+ putStringArray(KEY_ACTIVITIES, data.activityClasses.toTypedArray())
+ putStringArray(KEY_PREF_KEYS, data.visitedScreens.toTypedArray())
+ putString(KEY_LOCALE, data.locale?.toLanguageTag())
+ }
+
+ override fun decode(data: Bundle): GetPreferenceGraphRequest {
+ val activities = data.getStringArray(KEY_ACTIVITIES) ?: arrayOf()
+ val visitedScreens = data.getStringArray(KEY_PREF_KEYS) ?: arrayOf()
+ fun String?.toLocale() = if (this != null) Locale.forLanguageTag(this) else null
+ return GetPreferenceGraphRequest(
+ activities.toSet(),
+ visitedScreens.toSet(),
+ data.getString(KEY_LOCALE).toLocale(),
+ )
+ }
+
+ private const val KEY_ACTIVITIES = "activities"
+ private const val KEY_PREF_KEYS = "keys"
+ private const val KEY_LOCALE = "locale"
+}
+
+object PreferenceGraphProtoCodec : MessageCodec<PreferenceGraphProto> {
+ override fun encode(data: PreferenceGraphProto): Bundle =
+ Bundle(1).apply { putByteArray(KEY_GRAPH, data.toByteArray()) }
+
+ override fun decode(data: Bundle): PreferenceGraphProto =
+ PreferenceGraphProto.parseFrom(data.getByteArray(KEY_GRAPH)!!)
+
+ private const val KEY_GRAPH = "graph"
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
new file mode 100644
index 0000000..8c5d877
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:Suppress("DEPRECATION")
+
+package com.android.settingslib.graph
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.res.Configuration
+import android.os.Build
+import android.os.Bundle
+import android.preference.PreferenceActivity
+import android.util.Log
+import androidx.fragment.app.Fragment
+import androidx.preference.Preference
+import androidx.preference.PreferenceGroup
+import androidx.preference.PreferenceScreen
+import androidx.preference.TwoStatePreference
+import com.android.settingslib.graph.proto.PreferenceGraphProto
+import com.android.settingslib.graph.proto.PreferenceGroupProto
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget
+import com.android.settingslib.graph.proto.PreferenceScreenProto
+import com.android.settingslib.graph.proto.TextProto
+import com.android.settingslib.metadata.BooleanValue
+import com.android.settingslib.metadata.PersistentPreference
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.PreferenceHierarchy
+import com.android.settingslib.metadata.PreferenceHierarchyNode
+import com.android.settingslib.metadata.PreferenceMetadata
+import com.android.settingslib.metadata.PreferenceRestrictionProvider
+import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider
+import com.android.settingslib.metadata.PreferenceScreenMetadata
+import com.android.settingslib.metadata.PreferenceScreenRegistry
+import com.android.settingslib.metadata.PreferenceSummaryProvider
+import com.android.settingslib.metadata.PreferenceTitleProvider
+import com.android.settingslib.preference.PreferenceScreenFactory
+import com.android.settingslib.preference.PreferenceScreenProvider
+import java.util.Locale
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+private const val TAG = "PreferenceGraphBuilder"
+
+/**
+ * Builder of preference graph.
+ *
+ * Only activity in current application is supported. To create preference graph across
+ * applications, use [crawlPreferenceGraph].
+ */
+class PreferenceGraphBuilder
+private constructor(private val context: Context, private val request: GetPreferenceGraphRequest) {
+ private val preferenceScreenFactory by lazy {
+ PreferenceScreenFactory(context.ofLocale(request.locale))
+ }
+ private val builder by lazy { PreferenceGraphProto.newBuilder() }
+ private val visitedScreens = mutableSetOf<String>().apply { addAll(request.visitedScreens) }
+ private val includeValue = request.includeValue
+
+ private suspend fun init() {
+ for (activityClass in request.activityClasses) {
+ add(activityClass)
+ }
+ }
+
+ fun build() = builder.build()
+
+ /** Adds an activity to the graph. */
+ suspend fun <T> add(activityClass: Class<T>) where T : Activity, T : PreferenceScreenProvider =
+ addPreferenceScreenProvider(activityClass)
+
+ /**
+ * Adds an activity to the graph.
+ *
+ * Reflection is used to create the instance. To avoid security vulnerability, the code ensures
+ * given [activityClassName] must be declared as an <activity> entry in AndroidManifest.xml.
+ */
+ suspend fun add(activityClassName: String) {
+ try {
+ val intent = Intent()
+ intent.setClassName(context, activityClassName)
+ if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) ==
+ null) {
+ Log.e(TAG, "$activityClassName is not activity")
+ return
+ }
+ val activityClass = context.classLoader.loadClass(activityClassName)
+ if (addPreferenceScreenKeyProvider(activityClass)) return
+ if (PreferenceScreenProvider::class.java.isAssignableFrom(activityClass)) {
+ addPreferenceScreenProvider(activityClass)
+ } else {
+ Log.w(TAG, "$activityClass does not implement PreferenceScreenProvider")
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Fail to add $activityClassName", e)
+ }
+ }
+
+ private suspend fun addPreferenceScreenKeyProvider(activityClass: Class<*>): Boolean {
+ if (!PreferenceScreenBindingKeyProvider::class.java.isAssignableFrom(activityClass)) {
+ return false
+ }
+ val key = getPreferenceScreenKey { activityClass.newInstance() } ?: return false
+ if (addPreferenceScreenFromRegistry(key, activityClass)) {
+ builder.addRoots(key)
+ return true
+ }
+ return false
+ }
+
+ private suspend fun getPreferenceScreenKey(newInstance: () -> Any): String? =
+ withContext(Dispatchers.Main) {
+ try {
+ val instance = newInstance()
+ if (instance is PreferenceScreenBindingKeyProvider) {
+ return@withContext instance.getPreferenceScreenBindingKey(context)
+ } else {
+ Log.w(TAG, "$instance is not PreferenceScreenKeyProvider")
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "getPreferenceScreenKey failed", e)
+ }
+ null
+ }
+
+ private suspend fun addPreferenceScreenFromRegistry(
+ key: String,
+ activityClass: Class<*>,
+ ): Boolean {
+ val metadata = PreferenceScreenRegistry[key] ?: return false
+ if (!metadata.hasCompleteHierarchy()) return false
+ return addPreferenceScreenMetadata(metadata, activityClass)
+ }
+
+ private suspend fun addPreferenceScreenMetadata(
+ metadata: PreferenceScreenMetadata,
+ activityClass: Class<*>,
+ ): Boolean =
+ addPreferenceScreen(metadata.key, activityClass) {
+ preferenceScreenProto {
+ completeHierarchy = true
+ root = metadata.getPreferenceHierarchy(context).toProto(activityClass, true)
+ }
+ }
+
+ private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
+ Log.d(TAG, "add $activityClass")
+ createPreferenceScreen { activityClass.newInstance() }
+ ?.let {
+ addPreferenceScreen(Intent(context, activityClass), activityClass, it)
+ builder.addRoots(it.key)
+ }
+ }
+
+ /**
+ * Creates [PreferenceScreen].
+ *
+ * Androidx Activity/Fragment instance must be created in main thread, otherwise an exception is
+ * raised.
+ */
+ private suspend fun createPreferenceScreen(newInstance: () -> Any): PreferenceScreen? =
+ withContext(Dispatchers.Main) {
+ try {
+ val instance = newInstance()
+ Log.d(TAG, "createPreferenceScreen $instance")
+ if (instance is PreferenceScreenProvider) {
+ return@withContext instance.createPreferenceScreen(preferenceScreenFactory)
+ } else {
+ Log.w(TAG, "$instance is not PreferenceScreenProvider")
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "createPreferenceScreen failed", e)
+ }
+ return@withContext null
+ }
+
+ private suspend fun addPreferenceScreen(
+ intent: Intent,
+ activityClass: Class<*>,
+ preferenceScreen: PreferenceScreen?,
+ ) {
+ val key = preferenceScreen?.key
+ if (key.isNullOrEmpty()) {
+ Log.e(TAG, "$activityClass \"$preferenceScreen\" has no key")
+ return
+ }
+ @Suppress("CheckReturnValue")
+ addPreferenceScreen(key, activityClass) { preferenceScreen.toProto(intent, activityClass) }
+ }
+
+ private suspend fun addPreferenceScreen(
+ key: String,
+ activityClass: Class<*>,
+ preferenceScreenProvider: suspend () -> PreferenceScreenProto,
+ ): Boolean {
+ if (!visitedScreens.add(key)) {
+ Log.w(TAG, "$activityClass $key visited")
+ return false
+ }
+ val activityClassName = activityClass.name
+ val associatedKey = builder.getActivityScreensOrDefault(activityClassName, null)
+ if (associatedKey == null) {
+ builder.putActivityScreens(activityClassName, key)
+ } else if (associatedKey != key) {
+ Log.w(TAG, "Dup $activityClassName association, old: $associatedKey, new: $key")
+ }
+ builder.putScreens(key, preferenceScreenProvider())
+ return true
+ }
+
+ private suspend fun PreferenceScreen.toProto(
+ intent: Intent,
+ activityClass: Class<*>,
+ ): PreferenceScreenProto = preferenceScreenProto {
+ this.intent = intent.toProto()
+ root = (this@toProto as PreferenceGroup).toProto(activityClass)
+ }
+
+ private suspend fun PreferenceGroup.toProto(activityClass: Class<*>): PreferenceGroupProto =
+ preferenceGroupProto {
+ preference = (this@toProto as Preference).toProto(activityClass)
+ for (index in 0 until preferenceCount) {
+ val child = getPreference(index)
+ addPreferences(
+ preferenceOrGroupProto {
+ if (child is PreferenceGroup) {
+ group = child.toProto(activityClass)
+ } else {
+ preference = child.toProto(activityClass)
+ }
+ })
+ }
+ }
+
+ private suspend fun Preference.toProto(activityClass: Class<*>): PreferenceProto =
+ preferenceProto {
+ this@toProto.key?.let { key = it }
+ this@toProto.title?.let { title = textProto { string = it.toString() } }
+ this@toProto.summary?.let { summary = textProto { string = it.toString() } }
+ val preferenceExtras = peekExtras()
+ preferenceExtras?.let { extras = it.toProto() }
+ enabled = isEnabled
+ available = isVisible
+ persistent = isPersistent
+ if (includeValue && isPersistent && this@toProto is TwoStatePreference) {
+ value = preferenceValueProto { booleanValue = this@toProto.isChecked }
+ }
+ this@toProto.fragment.toActionTarget(activityClass, preferenceExtras)?.let {
+ actionTarget = it
+ return@preferenceProto
+ }
+ this@toProto.intent?.let { actionTarget = it.toActionTarget() }
+ }
+
+ private suspend fun PreferenceHierarchy.toProto(
+ activityClass: Class<*>,
+ isRoot: Boolean,
+ ): PreferenceGroupProto = preferenceGroupProto {
+ preference = toProto(this@toProto, activityClass, isRoot)
+ forEachAsync {
+ addPreferences(
+ preferenceOrGroupProto {
+ if (it is PreferenceHierarchy) {
+ group = it.toProto(activityClass, false)
+ } else {
+ preference = toProto(it, activityClass, false)
+ }
+ })
+ }
+ }
+
+ private suspend fun toProto(
+ node: PreferenceHierarchyNode,
+ activityClass: Class<*>,
+ isRoot: Boolean,
+ ) = preferenceProto {
+ val metadata = node.metadata
+ key = metadata.key
+ metadata.getTitleTextProto(isRoot)?.let { title = it }
+ if (metadata.summary != 0) {
+ summary = textProto { resourceId = metadata.summary }
+ } else {
+ (metadata as? PreferenceSummaryProvider)?.getSummary(context)?.let {
+ summary = textProto { string = it.toString() }
+ }
+ }
+ if (metadata.icon != 0) icon = metadata.icon
+ if (metadata.keywords != 0) keywords = metadata.keywords
+ val preferenceExtras = metadata.extras(context)
+ preferenceExtras?.let { extras = it.toProto() }
+ indexable = metadata.isIndexable(context)
+ enabled = metadata.isEnabled(context)
+ if (metadata is PreferenceAvailabilityProvider) {
+ available = metadata.isAvailable(context)
+ }
+ if (metadata is PreferenceRestrictionProvider) {
+ restricted = metadata.isRestricted(context)
+ }
+ persistent = metadata.isPersistent(context)
+ if (includeValue &&
+ persistent &&
+ metadata is BooleanValue &&
+ metadata is PersistentPreference<*>) {
+ metadata.storage(context).getValue(metadata.key, Boolean::class.javaObjectType)?.let {
+ value = preferenceValueProto { booleanValue = it }
+ }
+ }
+ if (metadata is PreferenceScreenMetadata) {
+ if (metadata.hasCompleteHierarchy()) {
+ @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata, activityClass)
+ } else {
+ metadata.fragmentClass()?.toActionTarget(activityClass, preferenceExtras)?.let {
+ actionTarget = it
+ }
+ }
+ }
+ metadata.intent(context)?.let { actionTarget = it.toActionTarget() }
+ }
+
+ private fun PreferenceMetadata.getTitleTextProto(isRoot: Boolean): TextProto? {
+ if (isRoot && this is PreferenceScreenMetadata) {
+ val titleRes = screenTitle
+ if (titleRes != 0) {
+ return textProto { resourceId = titleRes }
+ } else {
+ getScreenTitle(context)?.let {
+ return textProto { string = it.toString() }
+ }
+ }
+ } else {
+ val titleRes = title
+ if (titleRes != 0) {
+ return textProto { resourceId = titleRes }
+ }
+ }
+ return (this as? PreferenceTitleProvider)?.getTitle(context)?.let {
+ textProto { string = it.toString() }
+ }
+ }
+
+ private suspend fun String?.toActionTarget(
+ activityClass: Class<*>,
+ extras: Bundle?,
+ ): ActionTarget? {
+ if (this.isNullOrEmpty()) return null
+ try {
+ val fragmentClass = context.classLoader.loadClass(this)
+ if (Fragment::class.java.isAssignableFrom(fragmentClass)) {
+ @Suppress("UNCHECKED_CAST")
+ return (fragmentClass as Class<out Fragment>).toActionTarget(activityClass, extras)
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Cannot loadClass $this", e)
+ }
+ return null
+ }
+
+ private suspend fun Class<out Fragment>.toActionTarget(
+ activityClass: Class<*>,
+ extras: Bundle?,
+ ): ActionTarget {
+ val startIntent = Intent(context, activityClass)
+ startIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, name)
+ extras?.let { startIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, it) }
+ if (!PreferenceScreenProvider::class.java.isAssignableFrom(this) &&
+ !PreferenceScreenBindingKeyProvider::class.java.isAssignableFrom(this)) {
+ return actionTargetProto { intent = startIntent.toProto() }
+ }
+ val fragment =
+ withContext(Dispatchers.Main) {
+ return@withContext try {
+ newInstance().apply { arguments = extras }
+ } catch (e: Exception) {
+ Log.e(TAG, "Fail to instantiate fragment ${this@toActionTarget}", e)
+ null
+ }
+ }
+ if (fragment is PreferenceScreenBindingKeyProvider) {
+ val screenKey = fragment.getPreferenceScreenBindingKey(context)
+ if (screenKey != null && addPreferenceScreenFromRegistry(screenKey, activityClass)) {
+ return actionTargetProto { key = screenKey }
+ }
+ }
+ if (fragment is PreferenceScreenProvider) {
+ val screen = fragment.createPreferenceScreen(preferenceScreenFactory)
+ if (screen != null) {
+ addPreferenceScreen(startIntent, activityClass, screen)
+ return actionTargetProto { key = screen.key }
+ }
+ }
+ return actionTargetProto { intent = startIntent.toProto() }
+ }
+
+ private suspend fun Intent.toActionTarget(): ActionTarget {
+ if (component?.packageName == "") {
+ setClassName(context, component!!.className)
+ }
+ resolveActivity(context.packageManager)?.let {
+ if (it.packageName == context.packageName) {
+ add(it.className)
+ }
+ }
+ return actionTargetProto { intent = toProto() }
+ }
+
+ companion object {
+ suspend fun of(context: Context, request: GetPreferenceGraphRequest) =
+ PreferenceGraphBuilder(context, request).also { it.init() }
+ }
+}
+
+@SuppressLint("AppBundleLocaleChanges")
+internal fun Context.ofLocale(locale: Locale?): Context {
+ if (locale == null) return this
+ val baseConfig: Configuration = resources.configuration
+ val baseLocale =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ baseConfig.locales[0]
+ } else {
+ baseConfig.locale
+ }
+ if (locale == baseLocale) {
+ return this
+ }
+ val newConfig = Configuration(baseConfig)
+ newConfig.setLocale(locale)
+ return createConfigurationContext(newConfig)
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenManager.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenManager.kt
deleted file mode 100644
index 9231f40..0000000
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenManager.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.android.settingslib.graph
-
-import androidx.annotation.StringRes
-import androidx.annotation.XmlRes
-import androidx.preference.Preference
-import androidx.preference.PreferenceManager
-import androidx.preference.PreferenceScreen
-
-/** Manager to create and initialize preference screen. */
-class PreferenceScreenManager(private val preferenceManager: PreferenceManager) {
- private val context = preferenceManager.context
- // the map will preserve order
- private val updaters = mutableMapOf<String, PreferenceUpdater>()
- private val screenUpdaters = mutableListOf<PreferenceScreenUpdater>()
-
- /** Creates an empty [PreferenceScreen]. */
- fun createPreferenceScreen(): PreferenceScreen =
- preferenceManager.createPreferenceScreen(context)
-
- /** Creates [PreferenceScreen] from resource. */
- fun createPreferenceScreen(@XmlRes xmlRes: Int): PreferenceScreen =
- preferenceManager.inflateFromResource(context, xmlRes, null)
-
- /** Adds updater for given preference. */
- fun addPreferenceUpdater(@StringRes key: Int, updater: PreferenceUpdater) =
- addPreferenceUpdater(context.getString(key), updater)
-
- /** Adds updater for given preference. */
- fun addPreferenceUpdater(
- key: String,
- updater: PreferenceUpdater,
- ): PreferenceScreenManager {
- updaters.put(key, updater)?.let { if (it != updater) throw IllegalArgumentException() }
- return this
- }
-
- /** Adds updater for preference screen. */
- fun addPreferenceScreenUpdater(updater: PreferenceScreenUpdater): PreferenceScreenManager {
- screenUpdaters.add(updater)
- return this
- }
-
- /** Adds a list of updaters for preference screen. */
- fun addPreferenceScreenUpdater(
- vararg updaters: PreferenceScreenUpdater,
- ): PreferenceScreenManager {
- screenUpdaters.addAll(updaters)
- return this
- }
-
- /** Updates preference screen with registered updaters. */
- fun updatePreferenceScreen(preferenceScreen: PreferenceScreen) {
- for ((key, updater) in updaters) {
- preferenceScreen.findPreference<Preference>(key)?.let { updater.updatePreference(it) }
- }
- for (updater in screenUpdaters) {
- updater.updatePreferenceScreen(preferenceScreen)
- }
- }
-}
-
-/** Updater of [Preference]. */
-interface PreferenceUpdater {
- fun updatePreference(preference: Preference)
-}
-
-/** Updater of [PreferenceScreen]. */
-interface PreferenceScreenUpdater {
- fun updatePreferenceScreen(preferenceScreen: PreferenceScreen)
-}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenProvider.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenProvider.kt
deleted file mode 100644
index 9e4c1f6..0000000
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenProvider.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.android.settingslib.graph
-
-import android.content.Context
-import androidx.preference.PreferenceScreen
-
-/**
- * Interface to provide [PreferenceScreen].
- *
- * It is expected to be implemented by Activity/Fragment and the implementation needs to use
- * [Context] APIs (e.g. `getContext()`, `getActivity()`) with caution: preference screen creation
- * could happen in background service, where the Activity/Fragment lifecycle callbacks (`onCreate`,
- * `onDestroy`, etc.) are not invoked.
- */
-interface PreferenceScreenProvider {
-
- /**
- * Creates [PreferenceScreen].
- *
- * Preference screen creation could happen in background service. The implementation MUST use
- * given [context] instead of APIs like `getContext()`, `getActivity()`, etc.
- */
- fun createPreferenceScreen(
- context: Context,
- preferenceScreenManager: PreferenceScreenManager,
- ): PreferenceScreen?
-}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
new file mode 100644
index 0000000..d9b9590
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.android.settingslib.graph.proto.BundleProto
+import com.android.settingslib.graph.proto.BundleProto.BundleValue
+import com.android.settingslib.graph.proto.IntentProto
+import com.android.settingslib.graph.proto.TextProto
+import com.google.protobuf.ByteString
+
+fun TextProto.getText(context: Context): String? =
+ when {
+ hasResourceId() -> context.getString(resourceId)
+ hasString() -> string
+ else -> null
+ }
+
+fun Intent.toProto(): IntentProto = intentProto {
+ this@toProto.action?.let { action = it }
+ this@toProto.dataString?.let { data = it }
+ this@toProto.`package`?.let { pkg = it }
+ this@toProto.component?.let { component = it.flattenToShortString() }
+ this@toProto.flags.let { if (it != 0) flags = it }
+ this@toProto.extras?.let { extras = it.toProto() }
+ this@toProto.type?.let { mimeType = it }
+}
+
+fun Bundle.toProto(): BundleProto = bundleProto {
+ fun toProto(value: Any): BundleValue = bundleValueProto {
+ when (value) {
+ is String -> stringValue = value
+ is ByteArray -> bytesValue = ByteString.copyFrom(value)
+ is Int -> intValue = value
+ is Long -> longValue = value
+ is Boolean -> booleanValue = value
+ is Double -> doubleValue = value
+ is Bundle -> bundleValue = value.toProto()
+ else -> throw IllegalArgumentException("Unknown type: ${value.javaClass} $value")
+ }
+ }
+
+ for (key in keySet()) {
+ @Suppress("DEPRECATION") get(key)?.let { putValues(key, toProto(it)) }
+ }
+}
+
+fun BundleValue.stringify(): String =
+ when {
+ hasBooleanValue() -> "$valueCase"
+ hasBytesValue() -> "$bytesValue"
+ hasIntValue() -> "$intValue"
+ hasLongValue() -> "$longValue"
+ hasStringValue() -> stringValue
+ hasDoubleValue() -> "$doubleValue"
+ hasBundleValue() -> "$bundleValue"
+ else -> "Unknown"
+ }
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt
new file mode 100644
index 0000000..d7dae77
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import com.android.settingslib.graph.proto.BundleProto
+import com.android.settingslib.graph.proto.BundleProto.BundleValue
+import com.android.settingslib.graph.proto.IntentProto
+import com.android.settingslib.graph.proto.PreferenceGroupProto
+import com.android.settingslib.graph.proto.PreferenceOrGroupProto
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget
+import com.android.settingslib.graph.proto.PreferenceScreenProto
+import com.android.settingslib.graph.proto.PreferenceValueProto
+import com.android.settingslib.graph.proto.TextProto
+
+/** Returns root or null. */
+val PreferenceScreenProto.rootOrNull
+ get() = if (hasRoot()) root else null
+
+/** Kotlin DSL-style builder for [PreferenceScreenProto]. */
+@JvmSynthetic
+inline fun preferenceScreenProto(init: PreferenceScreenProto.Builder.() -> Unit) =
+ PreferenceScreenProto.newBuilder().also(init).build()
+
+/** Returns preference or null. */
+val PreferenceOrGroupProto.preferenceOrNull
+ get() = if (hasPreference()) preference else null
+
+/** Returns group or null. */
+val PreferenceOrGroupProto.groupOrNull
+ get() = if (hasGroup()) group else null
+
+/** Kotlin DSL-style builder for [PreferenceOrGroupProto]. */
+@JvmSynthetic
+inline fun preferenceOrGroupProto(init: PreferenceOrGroupProto.Builder.() -> Unit) =
+ PreferenceOrGroupProto.newBuilder().also(init).build()
+
+/** Returns preference or null. */
+val PreferenceGroupProto.preferenceOrNull
+ get() = if (hasPreference()) preference else null
+
+/** Kotlin DSL-style builder for [PreferenceGroupProto]. */
+@JvmSynthetic
+inline fun preferenceGroupProto(init: PreferenceGroupProto.Builder.() -> Unit) =
+ PreferenceGroupProto.newBuilder().also(init).build()
+
+/** Returns title or null. */
+val PreferenceProto.titleOrNull
+ get() = if (hasTitle()) title else null
+
+/** Returns summary or null. */
+val PreferenceProto.summaryOrNull
+ get() = if (hasSummary()) summary else null
+
+/** Returns actionTarget or null. */
+val PreferenceProto.actionTargetOrNull
+ get() = if (hasActionTarget()) actionTarget else null
+
+/** Kotlin DSL-style builder for [PreferenceProto]. */
+@JvmSynthetic
+inline fun preferenceProto(init: PreferenceProto.Builder.() -> Unit) =
+ PreferenceProto.newBuilder().also(init).build()
+
+/** Returns intent or null. */
+val ActionTarget.intentOrNull
+ get() = if (hasIntent()) intent else null
+
+/** Kotlin DSL-style builder for [ActionTarget]. */
+@JvmSynthetic
+inline fun actionTargetProto(init: ActionTarget.Builder.() -> Unit) =
+ ActionTarget.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [PreferenceValueProto]. */
+@JvmSynthetic
+inline fun preferenceValueProto(init: PreferenceValueProto.Builder.() -> Unit) =
+ PreferenceValueProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [TextProto]. */
+@JvmSynthetic
+inline fun textProto(init: TextProto.Builder.() -> Unit) = TextProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [IntentProto]. */
+@JvmSynthetic
+inline fun intentProto(init: IntentProto.Builder.() -> Unit) =
+ IntentProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [BundleProto]. */
+@JvmSynthetic
+inline fun bundleProto(init: BundleProto.Builder.() -> Unit) =
+ BundleProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [BundleValue]. */
+@JvmSynthetic
+inline fun bundleValueProto(init: BundleValue.Builder.() -> Unit) =
+ BundleValue.newBuilder().also(init).build()
diff --git a/packages/SettingsLib/Ipc/Android.bp b/packages/SettingsLib/Ipc/Android.bp
new file mode 100644
index 0000000..2c7209a
--- /dev/null
+++ b/packages/SettingsLib/Ipc/Android.bp
@@ -0,0 +1,34 @@
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "SettingsLibIpc-srcs",
+ srcs: ["src/**/*.kt"],
+}
+
+android_library {
+ name: "SettingsLibIpc",
+ defaults: [
+ "SettingsLintDefaults",
+ ],
+ srcs: [":SettingsLibIpc-srcs"],
+ static_libs: [
+ "androidx.collection_collection",
+ "guava",
+ "kotlinx-coroutines-android",
+ ],
+ kotlincflags: ["-Xjvm-default=all"],
+}
+
+android_library {
+ name: "SettingsLibIpc-testutils",
+ srcs: ["testutils/**/*.kt"],
+ static_libs: [
+ "Robolectric_all-target_upstream",
+ "SettingsLibIpc",
+ "androidx.test.core",
+ "flag-junit",
+ "kotlinx-coroutines-android",
+ ],
+}
diff --git a/packages/SettingsLib/Ipc/AndroidManifest.xml b/packages/SettingsLib/Ipc/AndroidManifest.xml
new file mode 100644
index 0000000..fc48a7d
--- /dev/null
+++ b/packages/SettingsLib/Ipc/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.ipc">
+
+ <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/packages/SettingsLib/Ipc/README.md b/packages/SettingsLib/Ipc/README.md
new file mode 100644
index 0000000..ea2c3a1b5
--- /dev/null
+++ b/packages/SettingsLib/Ipc/README.md
@@ -0,0 +1,116 @@
+# Service IPC library
+
+This library provides a kind of IPC (inter-process communication) framework
+based on Android
+[bound service](https://developer.android.com/develop/background-work/services/bound-services)
+with [Messenger](https://developer.android.com/reference/android/os/Messenger).
+
+Following benefits are offered by the library to improve and simplify IPC
+development:
+
+- Enforce permission check for every API implementation to avoid security
+ vulnerability.
+- Allow modular API development for better code maintenance (no more huge
+ Service class).
+- Prevent common mistakes, e.g. Service context leaking, ServiceConnection
+ management.
+
+## Overview
+
+In this manner of IPC,
+[Service](https://developer.android.com/reference/android/app/Service) works
+with [Handler](https://developer.android.com/reference/android/os/Handler) to
+deal with different types of
+[Message](https://developer.android.com/reference/android/os/Message) objects.
+
+Under the hood, each API is represented as a `Message` object:
+
+- [what](https://developer.android.com/reference/android/os/Message#what):
+ used to identify API.
+- [data](https://developer.android.com/reference/android/os/Message#getData\(\)):
+ payload of the API parameters and result.
+
+This could be mapped to the `ApiHandler` interface abstraction exactly.
+Specifically, the API implementation needs to provide:
+
+- An unique id for the API.
+- How to marshall/unmarshall the request and response.
+- Whether the given request is permitted.
+
+## Threading model
+
+`MessengerService` starts a dedicated
+[HandlerThread](https://developer.android.com/reference/android/os/HandlerThread)
+to handle requests. `ApiHandler` implementation uses Kotlin `suspend`, which
+allows flexible threading model on top of the
+[Kotlin coroutines](https://kotlinlang.org/docs/coroutines-overview.html).
+
+## Usage
+
+The service provider should extend `MessengerService` and provide API
+implementations. In `AndroidManifest.xml`, declare `<service>` with permission,
+intent filter, etc. if needed.
+
+Meanwhile, the service client implements `MessengerServiceClient` with API
+descriptors to make requests.
+
+Here is an example:
+
+```kotlin
+import android.app.Application
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import kotlinx.coroutines.runBlocking
+
+class EchoService :
+ MessengerService(
+ listOf(EchoApiImpl),
+ PermissionChecker { _, _, _ -> true },
+ )
+
+class EchoServiceClient(context: Context) : MessengerServiceClient(context) {
+ override val serviceIntentFactory: () -> Intent
+ get() = { Intent("example.intent.action.ECHO") }
+
+ fun echo(data: String?): String? =
+ runBlocking { invoke(context.packageName, EchoApi, data).await() }
+}
+
+object EchoApi : ApiDescriptor<String?, String?> {
+ private val codec =
+ object : MessageCodec<String?> {
+ override fun encode(data: String?) =
+ Bundle(1).apply { putString("data", data) }
+
+ override fun decode(data: Bundle): String? = data.getString("data", null)
+ }
+
+ override val id: Int
+ get() = 1
+
+ override val requestCodec: MessageCodec<String?>
+ get() = codec
+
+ override val responseCodec: MessageCodec<String?>
+ get() = codec
+}
+
+// This is not needed by EchoServiceClient.
+object EchoApiImpl : ApiHandler<String?, String?>,
+ ApiDescriptor<String?, String?> by EchoApi {
+ override suspend fun invoke(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: String?,
+ ): String? = request
+
+ override fun hasPermission(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: String?,
+ ): Boolean = (request?.length ?: 0) <= 5
+}
+```
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiException.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiException.kt
new file mode 100644
index 0000000..42772a4
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiException.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+/** Exception raised when handle request. */
+sealed class ApiException : Exception {
+ constructor() : super()
+
+ constructor(cause: Throwable?) : super(cause)
+
+ constructor(message: String, cause: Throwable?) : super(message, cause)
+}
+
+/** Exception occurred on client side. */
+open class ApiClientException : ApiException {
+ constructor() : super()
+
+ constructor(cause: Throwable?) : super(cause)
+
+ constructor(message: String, cause: Throwable?) : super(message, cause)
+}
+
+/** Client has already been closed. */
+class ClientClosedException : ApiClientException()
+
+/** Api to request is invalid, e.g. negative identity number. */
+class ClientInvalidApiException(message: String) : ApiClientException(message, null)
+
+/**
+ * Exception when bind service failed.
+ *
+ * This exception may be raised for following reasons:
+ * - Context used to bind service has finished its lifecycle (e.g. activity stopped).
+ * - Service not found.
+ * - Permission denied.
+ */
+class ClientBindServiceException(cause: Throwable?) : ApiClientException(cause)
+
+/** Exception when encode request. */
+class ClientEncodeException(cause: Throwable) : ApiClientException(cause)
+
+/** Exception when decode response. */
+class ClientDecodeException(cause: Throwable) : ApiClientException(cause)
+
+/** Exception when send message. */
+class ClientSendException(message: String, cause: Throwable) : ApiClientException(message, cause)
+
+/** Service returns unknown error code. */
+class ClientUnknownResponseCodeException(code: Int) :
+ ApiClientException("Unknown code: $code", null)
+
+/** Exception returned from service. */
+open class ApiServiceException : ApiException() {
+ companion object {
+ internal const val CODE_OK = 0
+ internal const val CODE_PERMISSION_DENIED = 1
+ internal const val CODE_UNKNOWN_API = 2
+ internal const val CODE_INTERNAL_ERROR = 3
+
+ internal fun of(code: Int): ApiServiceException? =
+ when (code) {
+ CODE_PERMISSION_DENIED -> ServicePermissionDeniedException()
+ CODE_UNKNOWN_API -> ServiceUnknownApiException()
+ CODE_INTERNAL_ERROR -> ServiceInternalException()
+ else -> null
+ }
+ }
+}
+
+/** Exception indicates the request is rejected due to permission deny. */
+class ServicePermissionDeniedException : ApiServiceException()
+
+/** Exception indicates API request is unknown. */
+class ServiceUnknownApiException : ApiServiceException()
+
+/** Exception indicates internal issue occurred when service handles the request. */
+class ServiceInternalException : ApiServiceException()
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
new file mode 100644
index 0000000..802141d
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import android.app.Application
+import android.os.Bundle
+
+/**
+ * Codec to marshall/unmarshall data between given type and [Bundle].
+ *
+ * The implementation must be threadsafe and stateless.
+ */
+interface MessageCodec<T> {
+ /** Converts given data to [Bundle]. */
+ fun encode(data: T): Bundle
+
+ /** Converts [Bundle] to an object of given data type. */
+ fun decode(data: Bundle): T
+}
+
+/**
+ * Descriptor of API.
+ *
+ * Used by both [MessengerService] and [MessengerServiceClient] to identify API and encode/decode
+ * messages.
+ */
+interface ApiDescriptor<Request, Response> {
+ /**
+ * Identity of the API.
+ *
+ * The id must be:
+ * - Positive: the negative numbers are reserved for internal messages.
+ * - Unique within the [MessengerService].
+ * - Permanent to achieve backward compatibility.
+ */
+ val id: Int
+
+ /** Codec for request. */
+ val requestCodec: MessageCodec<Request>
+
+ /** Codec for response. */
+ val responseCodec: MessageCodec<Response>
+}
+
+/**
+ * Handler of API.
+ *
+ * This is the API implementation portion, which is used by [MessengerService] only.
+ * [MessengerServiceClient] does NOT need this interface at all to make request.
+ *
+ * The implementation must be threadsafe.
+ */
+interface ApiHandler<Request, Response> : ApiDescriptor<Request, Response> {
+ /**
+ * Returns if the request is permitted.
+ *
+ * @return `false` if permission is denied, otherwise `true`
+ */
+ fun hasPermission(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: Request,
+ ): Boolean
+
+ /**
+ * Invokes the API.
+ *
+ * The API is invoked from Service handler thread, do not perform time-consuming task. Start
+ * coroutine in another thread if it takes time to complete.
+ */
+ suspend fun invoke(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: Request,
+ ): Response
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessageCodecs.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessageCodecs.kt
new file mode 100644
index 0000000..4b7572b
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessageCodecs.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import android.os.Bundle
+
+/** [MessageCodec] for [Int]. */
+object IntMessageCodec : MessageCodec<Int> {
+ override fun encode(data: Int): Bundle = Bundle(1).apply { putInt(null, data) }
+
+ override fun decode(data: Bundle): Int = data.getInt(null)
+}
+
+/** [MessageCodec] for [Set<Int>]. */
+class IntSetMessageCodec : MessageCodec<Set<Int>> {
+ override fun encode(data: Set<Int>): Bundle =
+ Bundle(1).apply { putIntArray(null, data.toIntArray()) }
+
+ override fun decode(data: Bundle): Set<Int> = data.getIntArray(null)?.toSet() ?: setOf()
+}
+
+/** [MessageCodec] for [Set<String>]. */
+class StringSetMessageCodec : MessageCodec<Set<String>> {
+ override fun encode(data: Set<String>): Bundle =
+ Bundle(1).apply { putStringArray(null, data.toTypedArray()) }
+
+ override fun decode(data: Bundle): Set<String> = data.getStringArray(null)?.toSet() ?: setOf()
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerService.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerService.kt
new file mode 100644
index 0000000..0bdae38
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerService.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import android.app.Application
+import android.app.Service
+import android.content.Intent
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.IBinder
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
+import android.os.Process
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+
+/**
+ * [Messenger] based bound service for IPC.
+ *
+ * A dedicated [HandlerThread] is created to handle all requests.
+ *
+ * @param apiHandlers API handlers associated with the service
+ * @param permissionChecker Checker for permission
+ * @param name name of the handler thread
+ */
+open class MessengerService(
+ private val apiHandlers: List<ApiHandler<*, *>>,
+ private val permissionChecker: PermissionChecker,
+ name: String = TAG,
+) : Service() {
+ @VisibleForTesting internal val handlerThread = HandlerThread(name)
+ @VisibleForTesting internal lateinit var handler: IncomingHandler
+ private lateinit var messenger: Messenger
+
+ override fun onCreate() {
+ super.onCreate()
+ handlerThread.start()
+ handler =
+ IncomingHandler(
+ handlerThread.looper,
+ applicationContext as Application,
+ apiHandlers.toSortedArray(),
+ permissionChecker,
+ )
+ messenger = Messenger(handler)
+ Log.i(TAG, "onCreate HandlerThread ${handlerThread.threadId}")
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ // this method is executed only once even there is more than 1 client
+ Log.i(TAG, "onBind $intent")
+ return messenger.binder
+ }
+
+ override fun onUnbind(intent: Intent): Boolean {
+ // invoked when ALL clients are unbound
+ Log.i(TAG, "onUnbind $intent")
+ handler.coroutineScope.cancel()
+ return super.onUnbind(intent)
+ }
+
+ override fun onDestroy() {
+ Log.i(TAG, "onDestroy HandlerThread ${handlerThread.threadId}")
+ handlerThread.quitSafely()
+ super.onDestroy()
+ }
+
+ @VisibleForTesting
+ internal class IncomingHandler(
+ looper: Looper,
+ private val application: Application,
+ private val apiHandlers: Array<ApiHandler<*, *>>,
+ private val permissionChecker: PermissionChecker,
+ ) : Handler(looper) {
+ @VisibleForTesting internal val myUid = Process.myUid()
+ val coroutineScope = CoroutineScope(asCoroutineDispatcher().immediate + SupervisorJob())
+
+ override fun handleMessage(msg: Message) {
+ coroutineScope.launch { handle(msg) }
+ }
+
+ @VisibleForTesting
+ internal suspend fun handle(msg: Message) {
+ Log.d(TAG, "receive request $msg")
+ val replyTo = msg.replyTo
+ if (replyTo == null) {
+ Log.e(TAG, "Ignore msg without replyTo: $msg")
+ return
+ }
+ val apiId = msg.what
+ val txnId = msg.arg1
+ val callingUid = msg.sendingUid
+ val data = msg.data
+ // WARNING: never access "msg" beyond this point as it may be recycled by Looper
+ val response = Message.obtain(null, apiId, txnId, ApiServiceException.CODE_OK)
+ try {
+ if (permissionChecker.check(application, myUid, callingUid)) {
+ @Suppress("UNCHECKED_CAST")
+ val apiHandler = findApiHandler(apiId) as? ApiHandler<Any, Any>
+ if (apiHandler != null) {
+ val request = apiHandler.requestCodec.decode(data)
+ if (apiHandler.hasPermission(application, myUid, callingUid, request)) {
+ val result = apiHandler.invoke(application, myUid, callingUid, request)
+ response.data = apiHandler.responseCodec.encode(result)
+ } else {
+ response.arg2 = ApiServiceException.CODE_PERMISSION_DENIED
+ }
+ } else {
+ response.arg2 = ApiServiceException.CODE_UNKNOWN_API
+ Log.e(TAG, "Unknown request [txnId=$txnId,apiId=$apiId]")
+ }
+ } else {
+ response.arg2 = ApiServiceException.CODE_PERMISSION_DENIED
+ }
+ } catch (e: Exception) {
+ response.arg2 = ApiServiceException.CODE_INTERNAL_ERROR
+ Log.e(TAG, "Internal error when handle [txnId=$txnId,apiId=$apiId]", e)
+ }
+ try {
+ replyTo.send(response)
+ } catch (e: Exception) {
+ Log.w(TAG, "Fail to send response for [txnId=$txnId,apiId=$apiId]", e)
+ // nothing to do
+ }
+ }
+
+ @VisibleForTesting
+ internal fun findApiHandler(id: Int): ApiHandler<*, *>? {
+ var low = 0
+ var high = apiHandlers.size
+ while (low < high) {
+ val mid = (low + high).ushr(1) // safe from overflows
+ val api = apiHandlers[mid]
+ when {
+ api.id < id -> low = mid + 1
+ api.id > id -> high = mid
+ else -> return api
+ }
+ }
+ return null
+ }
+ }
+
+ companion object {
+ @VisibleForTesting internal const val TAG = "MessengerService"
+ }
+}
+
+@VisibleForTesting
+internal fun List<ApiHandler<*, *>>.toSortedArray() =
+ toTypedArray().also { array ->
+ if (array.isEmpty()) return@also
+ array.sortBy { it.id }
+ if (array[0].id < 0) throw IllegalArgumentException("negative id: ${array[0]}")
+ for (index in 1 until array.size) {
+ if (array[index - 1].id == array[index].id) {
+ throw IllegalArgumentException("conflict id: ${array[index - 1]} ${array[index]}")
+ }
+ }
+ }
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
new file mode 100644
index 0000000..7ffefed
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.Bundle
+import android.os.DeadObjectException
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.IBinder
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
+import android.util.Log
+import androidx.annotation.OpenForTesting
+import androidx.annotation.VisibleForTesting
+import androidx.collection.ArrayMap
+import com.google.common.base.Ticker
+import java.util.concurrent.atomic.AtomicInteger
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CompletionHandler
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.DisposableHandle
+
+/**
+ * Client to communicate with [MessengerService].
+ *
+ * A dedicated [HandlerThread] is created to handle requests **sequentially**, there is only one
+ * ongoing request per package.
+ *
+ * Must call [close] before [context] is destroyed to avoid context leaking. Note that
+ * [MessengerService] is automatically unbound when context lifecycle is stopped. Further request
+ * will result in service binding exception.
+ *
+ * @param context context used for service binding, note that context lifecycle affects the IPC
+ * service lifecycle
+ * @param serviceConnectionIdleMs idle time in milliseconds before closing the service connection
+ * @param name name of the handler thread
+ */
+abstract class MessengerServiceClient
+@JvmOverloads
+constructor(
+ protected val context: Context,
+ private val serviceConnectionIdleMs: Long = 30000L,
+ name: String = TAG,
+ private val metricsLogger: MetricsLogger? = null,
+) : AutoCloseable {
+ /** Per package [ServiceConnection]. */
+ @VisibleForTesting internal val messengers = ArrayMap<String, Connection>()
+ private val handlerThread = HandlerThread(name)
+ @VisibleForTesting internal val handler: Handler
+
+ init {
+ handlerThread.start()
+ val looper = handlerThread.looper
+ handler = Handler(looper)
+ }
+
+ /**
+ * Factory for service [Intent] creation.
+ *
+ * A typical implementation is create [Intent] with specific action.
+ */
+ protected abstract val serviceIntentFactory: () -> Intent
+
+ override fun close() = close(true)
+
+ fun close(join: Boolean) {
+ handler.post {
+ val exception = ClientClosedException()
+ val connections = messengers.values.toTypedArray()
+ for (connection in connections) connection.close(exception)
+ }
+ handlerThread.quitSafely()
+ if (join) handlerThread.join()
+ }
+
+ /**
+ * Invokes given API.
+ *
+ * @param packageName package name of the target service
+ * @param apiDescriptor descriptor of API
+ * @param request request parameter
+ * @return Deferred object of the response, which could be used for [Deferred.await],
+ * [Deferred.cancel], etc.
+ * @exception ApiException
+ */
+ // TODO: support timeout
+ fun <Request, Response> invoke(
+ packageName: String,
+ apiDescriptor: ApiDescriptor<Request, Response>,
+ request: Request,
+ ): Deferred<Response> {
+ if (apiDescriptor.id < 0) throw ClientInvalidApiException("Invalid id: ${apiDescriptor.id}")
+ if (
+ packageName == context.packageName &&
+ Looper.getMainLooper().thread === Thread.currentThread()
+ ) {
+ // Deadlock as it might involve service creation, which requires main thread
+ throw IllegalStateException("Invoke on main thread causes deadlock")
+ }
+ val wrapper = RequestWrapper(packageName, apiDescriptor, request, txnId.getAndIncrement())
+ metricsLogger?.run {
+ wrapper.logIpcEvent(this, IpcEvent.ENQUEUED)
+ wrapper.deferred.invokeOnCompletion {
+ wrapper.logIpcEvent(this, IpcEvent.COMPLETED, it)
+ }
+ }
+ if (!handler.post { getConnection(packageName).enqueueRequest(wrapper) }) {
+ wrapper.completeExceptionally(ClientClosedException())
+ }
+ return wrapper.deferred
+ }
+
+ private fun getConnection(packageName: String) =
+ messengers.getOrPut(packageName) {
+ Connection(
+ handler.looper,
+ context,
+ packageName,
+ serviceConnectionIdleMs,
+ serviceIntentFactory,
+ messengers,
+ metricsLogger,
+ )
+ }
+
+ @VisibleForTesting
+ internal data class RequestWrapper<Request, Response>(
+ val packageName: String,
+ val apiDescriptor: ApiDescriptor<Request, Response>,
+ val request: Request,
+ val txnId: Int,
+ val deferred: CompletableDeferred<Response> = CompletableDeferred(),
+ ) {
+ val data: Bundle
+ get() = request.let { apiDescriptor.requestCodec.encode(it) }
+
+ fun completeExceptionally(e: Exception) {
+ deferred.completeExceptionally(e)
+ }
+
+ fun logIpcEvent(
+ metricsLogger: MetricsLogger,
+ event: @IpcEvent Int,
+ cause: Throwable? = null,
+ ) {
+ try {
+ metricsLogger.logIpcEvent(
+ packageName,
+ txnId,
+ apiDescriptor.id,
+ event,
+ cause,
+ ticker.read(),
+ )
+ } catch (e: Exception) {
+ Log.e(TAG, "fail to log ipc event: $event", e)
+ }
+ }
+ }
+
+ // NOTE: All ServiceConnection callbacks are invoked from main thread.
+ @OpenForTesting
+ @VisibleForTesting
+ internal open class Connection(
+ looper: Looper,
+ private val context: Context,
+ private val packageName: String,
+ private val serviceConnectionIdleMs: Long,
+ private val serviceIntentFactory: () -> Intent,
+ private val messengers: ArrayMap<String, Connection>,
+ private val metricsLogger: MetricsLogger?,
+ ) : Handler(looper), ServiceConnection {
+ private val clientMessenger = Messenger(this)
+ internal val pendingRequests = ArrayDeque<RequestWrapper<*, *>>()
+ internal var serviceMessenger: Messenger? = null
+ internal open var connectionState: Int = STATE_INIT
+
+ internal var disposableHandle: DisposableHandle? = null
+ private val requestCompletionHandler =
+ object : CompletionHandler {
+ override fun invoke(cause: Throwable?) {
+ sendEmptyMessage(MSG_CHECK_REQUEST_STATE)
+ }
+ }
+
+ override fun handleMessage(msg: Message) {
+ if (msg.what < 0) {
+ handleClientMessage(msg)
+ return
+ }
+ Log.d(TAG, "receive response $msg")
+ val request = pendingRequests.removeFirstOrNull()
+ if (request == null) {
+ Log.w(TAG, "Pending request is empty when got response")
+ return
+ }
+ if (msg.arg1 != request.txnId || request.apiDescriptor.id != msg.what) {
+ Log.w(TAG, "Mismatch ${request.apiDescriptor.id}, response=$msg")
+ // add request back for retry
+ pendingRequests.addFirst(request)
+ return
+ }
+ handleServiceMessage(request, msg)
+ }
+
+ internal open fun handleClientMessage(msg: Message) {
+ when (msg.what) {
+ MSG_ON_SERVICE_CONNECTED -> {
+ if (connectionState == STATE_BINDING) {
+ connectionState = STATE_CONNECTED
+ serviceMessenger = Messenger(msg.obj as IBinder)
+ drainPendingRequests()
+ } else {
+ Log.w(TAG, "Got onServiceConnected when state is $connectionState")
+ }
+ }
+ MSG_REBIND_SERVICE -> {
+ if (pendingRequests.isEmpty()) {
+ removeMessages(MSG_CLOSE_ON_IDLE)
+ close(null)
+ } else {
+ // died when binding, reset state for rebinding
+ if (msg.obj != null && connectionState == STATE_BINDING) {
+ connectionState = STATE_CONNECTED
+ }
+ rebindService()
+ }
+ }
+ MSG_CLOSE_ON_IDLE -> {
+ if (pendingRequests.isEmpty()) close(null)
+ }
+ MSG_CHECK_REQUEST_STATE -> {
+ val request = pendingRequests.firstOrNull()
+ if (request != null && request.deferred.isCompleted) {
+ drainPendingRequests()
+ }
+ }
+ else -> Log.e(TAG, "Unknown msg: $msg")
+ }
+ }
+
+ internal open fun handleServiceMessage(request: RequestWrapper<*, *>, response: Message) {
+ @Suppress("UNCHECKED_CAST") val deferred = request.deferred as CompletableDeferred<Any?>
+ if (deferred.isCompleted) {
+ drainPendingRequests()
+ return
+ }
+ metricsLogger?.let { request.logIpcEvent(it, IpcEvent.RESPONSE_RECEIVED) }
+ disposableHandle?.dispose()
+ if (response.arg2 == ApiServiceException.CODE_OK) {
+ try {
+ deferred.complete(request.apiDescriptor.responseCodec.decode(response.data))
+ } catch (e: Exception) {
+ request.completeExceptionally(ClientDecodeException(e))
+ }
+ } else {
+ val errorCode = response.arg2
+ val exception = ApiServiceException.of(errorCode)
+ if (exception != null) {
+ request.completeExceptionally(exception)
+ } else {
+ request.completeExceptionally(ClientUnknownResponseCodeException(errorCode))
+ }
+ }
+ drainPendingRequests()
+ }
+
+ fun enqueueRequest(request: RequestWrapper<*, *>) {
+ if (connectionState == STATE_CLOSED) {
+ request.completeExceptionally(ClientClosedException())
+ return
+ }
+ pendingRequests.add(request)
+ if (pendingRequests.size == 1) {
+ removeMessages(MSG_CLOSE_ON_IDLE)
+ drainPendingRequests()
+ }
+ }
+
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ Log.i(TAG, "onServiceConnected $name")
+ metricsLogger?.logServiceEvent(ServiceEvent.ON_SERVICE_CONNECTED)
+ sendMessage(obtainMessage(MSG_ON_SERVICE_CONNECTED, service))
+ }
+
+ override fun onServiceDisconnected(name: ComponentName) {
+ // Service process crashed or killed, the connection remains alive, will receive
+ // onServiceConnected when the Service is next running
+ Log.i(TAG, "onServiceDisconnected $name")
+ metricsLogger?.logServiceEvent(ServiceEvent.ON_SERVICE_DISCONNECTED)
+ sendMessage(obtainMessage(MSG_REBIND_SERVICE))
+ }
+
+ override fun onBindingDied(name: ComponentName) {
+ Log.i(TAG, "onBindingDied $name")
+ metricsLogger?.logServiceEvent(ServiceEvent.ON_BINDING_DIED)
+ // When service is connected and peer happens to be updated, both onServiceDisconnected
+ // and onBindingDied callbacks are invoked.
+ if (!hasMessages(MSG_REBIND_SERVICE)) {
+ sendMessage(obtainMessage(MSG_REBIND_SERVICE, true))
+ }
+ }
+
+ internal open fun drainPendingRequests() {
+ disposableHandle = null
+ if (pendingRequests.isEmpty()) {
+ closeOnIdle(serviceConnectionIdleMs)
+ return
+ }
+ val serviceMessenger = this.serviceMessenger
+ if (serviceMessenger == null) {
+ bindService()
+ return
+ }
+ do {
+ val request = pendingRequests.first()
+ if (request.deferred.isCompleted) {
+ pendingRequests.removeFirst()
+ } else {
+ sendServiceMessage(serviceMessenger, request)
+ return
+ }
+ } while (pendingRequests.isNotEmpty())
+ closeOnIdle(serviceConnectionIdleMs)
+ }
+
+ internal open fun closeOnIdle(idleMs: Long) {
+ if (idleMs <= 0 || !sendEmptyMessageDelayed(MSG_CLOSE_ON_IDLE, idleMs)) {
+ close(null)
+ }
+ }
+
+ internal open fun sendServiceMessage(
+ serviceMessenger: Messenger,
+ request: RequestWrapper<*, *>,
+ ) {
+ fun completeExceptionally(exception: Exception) {
+ pendingRequests.removeFirst()
+ request.completeExceptionally(exception)
+ drainPendingRequests()
+ }
+ val message =
+ obtainMessage(request.apiDescriptor.id, request.txnId, 0).apply {
+ replyTo = clientMessenger
+ }
+ try {
+ message.data = request.data
+ } catch (e: Exception) {
+ completeExceptionally(ClientEncodeException(e))
+ return
+ }
+ Log.d(TAG, "send $message")
+ try {
+ sendServiceMessage(serviceMessenger, message)
+ metricsLogger?.let { request.logIpcEvent(it, IpcEvent.REQUEST_SENT) }
+ disposableHandle = request.deferred.invokeOnCompletion(requestCompletionHandler)
+ } catch (e: DeadObjectException) {
+ Log.w(TAG, "Got DeadObjectException")
+ rebindService()
+ } catch (e: Exception) {
+ completeExceptionally(ClientSendException("Fail to send $message", e))
+ }
+ }
+
+ @Throws(Exception::class)
+ internal open fun sendServiceMessage(serviceMessenger: Messenger, message: Message) =
+ serviceMessenger.send(message)
+
+ internal fun bindService() {
+ if (connectionState == STATE_BINDING || connectionState == STATE_CLOSED) {
+ Log.w(TAG, "Ignore bindService $packageName, state: $connectionState")
+ return
+ }
+ connectionState = STATE_BINDING
+ Log.i(TAG, "bindService $packageName")
+ val intent = serviceIntentFactory.invoke()
+ intent.setPackage(packageName)
+ metricsLogger?.logServiceEvent(ServiceEvent.BIND_SERVICE)
+ bindService(intent)?.let { close(it) }
+ }
+
+ private fun bindService(intent: Intent): Exception? =
+ try {
+ if (context.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+ null
+ } else {
+ ClientBindServiceException(null)
+ }
+ } catch (e: Exception) {
+ ClientBindServiceException(e)
+ }
+
+ internal open fun rebindService() {
+ Log.i(TAG, "rebindService $packageName")
+ metricsLogger?.logServiceEvent(ServiceEvent.REBIND_SERVICE)
+ unbindService()
+ bindService()
+ }
+
+ internal fun close(exception: Exception?) {
+ Log.i(TAG, "close connection $packageName", exception)
+ connectionState = STATE_CLOSED
+ messengers.remove(packageName, this)
+ unbindService()
+ if (pendingRequests.isNotEmpty()) {
+ val reason = exception ?: ClientClosedException()
+ do {
+ pendingRequests.removeFirst().deferred.completeExceptionally(reason)
+ } while (pendingRequests.isNotEmpty())
+ }
+ }
+
+ private fun unbindService() {
+ disposableHandle?.dispose()
+ disposableHandle = null
+ serviceMessenger = null
+ metricsLogger?.logServiceEvent(ServiceEvent.UNBIND_SERVICE)
+ try {
+ // "IllegalArgumentException: Service not registered" may be raised when peer app is
+ // just updated (e.g. upgraded)
+ context.unbindService(this)
+ } catch (e: Exception) {
+ Log.w(TAG, "exception raised when unbindService", e)
+ }
+ }
+
+ private fun MetricsLogger.logServiceEvent(event: @ServiceEvent Int) {
+ try {
+ logServiceEvent(packageName, event, ticker.read())
+ } catch (e: Exception) {
+ Log.e(TAG, "fail to log service event: $event", e)
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "MessengerServiceClient"
+ private val ticker: Ticker by lazy { Ticker.systemTicker() }
+
+ @VisibleForTesting internal const val STATE_INIT = 0
+ @VisibleForTesting internal const val STATE_BINDING = 1
+ @VisibleForTesting internal const val STATE_CONNECTED = 2
+ @VisibleForTesting internal const val STATE_CLOSED = 3
+
+ @VisibleForTesting internal const val MSG_ON_SERVICE_CONNECTED = -1
+ @VisibleForTesting internal const val MSG_REBIND_SERVICE = -2
+ @VisibleForTesting internal const val MSG_CLOSE_ON_IDLE = -3
+ @VisibleForTesting internal const val MSG_CHECK_REQUEST_STATE = -4
+
+ @VisibleForTesting internal val txnId = AtomicInteger()
+ }
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MetricsLogger.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MetricsLogger.kt
new file mode 100644
index 0000000..795a920
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MetricsLogger.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import androidx.annotation.IntDef
+
+/** Interface for metrics logging. */
+interface MetricsLogger {
+
+ /**
+ * Logs service connection event.
+ *
+ * @param packageName package name of the service connection
+ * @param event service event type
+ * @param elapsedRealtimeNanos nanoseconds since boot, including time spent in sleep
+ * @see [android.os.SystemClock.elapsedRealtimeNanos]
+ */
+ fun logServiceEvent(packageName: String, event: @ServiceEvent Int, elapsedRealtimeNanos: Long)
+
+ /**
+ * Logs ipc call event.
+ *
+ * @param packageName package name of the service connection
+ * @param txnId unique transaction id of the ipc call
+ * @param ipc ipc API id
+ * @param event ipc event type
+ * @param cause cause when ipc request completed, provided only when [event] is
+ * [IpcEvent.COMPLETED]
+ * @param elapsedRealtimeNanos nanoseconds since boot, including time spent in sleep
+ * @see [android.os.SystemClock.elapsedRealtimeNanos]
+ */
+ fun logIpcEvent(
+ packageName: String,
+ txnId: Int,
+ ipc: Int,
+ event: Int,
+ cause: Throwable?,
+ elapsedRealtimeNanos: Long,
+ )
+}
+
+/** Service connection events (for client). */
+@Target(AnnotationTarget.TYPE)
+@IntDef(
+ ServiceEvent.BIND_SERVICE,
+ ServiceEvent.UNBIND_SERVICE,
+ ServiceEvent.REBIND_SERVICE,
+ ServiceEvent.ON_SERVICE_CONNECTED,
+ ServiceEvent.ON_SERVICE_DISCONNECTED,
+ ServiceEvent.ON_BINDING_DIED,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class ServiceEvent {
+ companion object {
+ /** Event of [android.content.Context.bindService] call. */
+ const val BIND_SERVICE = 0
+
+ /** Event of [android.content.Context.unbindService] call. */
+ const val UNBIND_SERVICE = 1
+
+ /** Event to rebind service. */
+ const val REBIND_SERVICE = 2
+
+ /** Event of [android.content.ServiceConnection.onServiceConnected] callback. */
+ const val ON_SERVICE_CONNECTED = 3
+
+ /** Event of [android.content.ServiceConnection.onServiceDisconnected] callback. */
+ const val ON_SERVICE_DISCONNECTED = 4
+
+ /** Event of [android.content.ServiceConnection.onBindingDied] callback. */
+ const val ON_BINDING_DIED = 5
+ }
+}
+
+/** Events of a ipc call. */
+@Target(AnnotationTarget.TYPE)
+@IntDef(IpcEvent.ENQUEUED, IpcEvent.REQUEST_SENT, IpcEvent.RESPONSE_RECEIVED, IpcEvent.COMPLETED)
+@Retention(AnnotationRetention.SOURCE)
+annotation class IpcEvent {
+ companion object {
+ /** Event of IPC request enqueued. */
+ const val ENQUEUED = 0
+
+ /** Event of IPC request has been sent to service. */
+ const val REQUEST_SENT = 1
+
+ /** Event of IPC response received from service. */
+ const val RESPONSE_RECEIVED = 2
+
+ /** Event of IPC request completed. */
+ const val COMPLETED = 3
+ }
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/PermissionChecker.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/PermissionChecker.kt
new file mode 100644
index 0000000..da9c955
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/PermissionChecker.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import android.app.Application
+import android.content.pm.PackageManager
+import androidx.collection.mutableIntIntMapOf
+
+/** Checker for permission. */
+fun interface PermissionChecker {
+ /**
+ * Checks permission.
+ *
+ * @param application application context
+ * @param myUid uid of current process
+ * @param callingUid uid of peer process
+ */
+ fun check(application: Application, myUid: Int, callingUid: Int): Boolean
+}
+
+/** Verifies apk signatures as permission check. */
+class SignatureChecker : PermissionChecker {
+ private val cache = mutableIntIntMapOf()
+
+ override fun check(application: Application, myUid: Int, callingUid: Int): Boolean =
+ cache.getOrPut(callingUid) {
+ application.packageManager.checkSignatures(myUid, callingUid)
+ } == PackageManager.SIGNATURE_MATCH
+}
diff --git a/packages/SettingsLib/Ipc/testutils/com/android/settingslib/ipc/MessengerServiceRule.kt b/packages/SettingsLib/Ipc/testutils/com/android/settingslib/ipc/MessengerServiceRule.kt
new file mode 100644
index 0000000..8b2deaf
--- /dev/null
+++ b/packages/SettingsLib/Ipc/testutils/com/android/settingslib/ipc/MessengerServiceRule.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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.ipc
+
+import android.app.Application
+import android.app.Service
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Build
+import android.os.Looper
+import androidx.test.core.app.ApplicationProvider
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import org.robolectric.Robolectric
+import org.robolectric.Shadows
+import org.robolectric.android.controller.ServiceController
+
+/** Rule for messenger service testing. */
+open class MessengerServiceRule<C : MessengerServiceClient>(
+ private val serviceClass: Class<out MessengerService>,
+ val client: C,
+) : TestWatcher() {
+ val application: Application = ApplicationProvider.getApplicationContext()
+ val isRobolectric = Build.FINGERPRINT.contains("robolectric")
+
+ private var serviceController: ServiceController<out Service>? = null
+
+ override fun starting(description: Description) {
+ if (isRobolectric) {
+ runBlocking { setupRobolectricService() }
+ }
+ }
+
+ override fun finished(description: Description) {
+ client.close()
+ if (isRobolectric) {
+ runBlocking {
+ withContext(Dispatchers.Main) { serviceController?.run { unbind().destroy() } }
+ }
+ }
+ }
+
+ private suspend fun setupRobolectricService() {
+ if (Thread.currentThread() == Looper.getMainLooper().thread) {
+ throw IllegalStateException(
+ "To avoid deadlock, run test with @LooperMode(LooperMode.Mode.INSTRUMENTATION_TEST)"
+ )
+ }
+ withContext(Dispatchers.Main) {
+ serviceController = Robolectric.buildService(serviceClass)
+ val service = serviceController!!.create().get()
+ Shadows.shadowOf(application).apply {
+ setComponentNameAndServiceForBindService(
+ ComponentName(application, serviceClass),
+ service.onBind(Intent(application, serviceClass)),
+ )
+ setBindServiceCallsOnServiceConnectedDirectly(true)
+ setUnbindServiceCallsOnServiceDisconnected(false)
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index ffd2879..83d657e 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -22,7 +22,7 @@
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
-import com.android.settingslib.spa.gallery.card.CardPageProvider
+import com.android.settingslib.spa.gallery.banner.BannerPageProvider
import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
import com.android.settingslib.spa.gallery.dialog.NavDialogProvider
@@ -107,7 +107,7 @@
SettingsTextFieldPasswordPageProvider,
SearchScaffoldPageProvider,
SuwScaffoldPageProvider,
- CardPageProvider,
+ BannerPageProvider,
CopyablePageProvider,
),
rootPages = listOf(
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/banner/BannerPageProvider.kt
similarity index 77%
rename from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
rename to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/banner/BannerPageProvider.kt
index 5dd7caf..6edd917 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/banner/BannerPageProvider.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settingslib.spa.gallery.card
+package com.android.settingslib.spa.gallery.banner
import android.os.Bundle
import androidx.compose.foundation.clickable
@@ -46,39 +46,39 @@
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.gallery.R
-import com.android.settingslib.spa.widget.card.CardButton
-import com.android.settingslib.spa.widget.card.CardModel
-import com.android.settingslib.spa.widget.card.SettingsCard
-import com.android.settingslib.spa.widget.card.SettingsCardContent
-import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
+import com.android.settingslib.spa.widget.banner.BannerButton
+import com.android.settingslib.spa.widget.banner.BannerModel
+import com.android.settingslib.spa.widget.banner.SettingsBanner
+import com.android.settingslib.spa.widget.banner.SettingsBannerContent
+import com.android.settingslib.spa.widget.banner.SettingsCollapsibleBanner
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
-object CardPageProvider : SettingsPageProvider {
- override val name = "Card"
+object BannerPageProvider : SettingsPageProvider {
+ override val name = "Banner"
override fun getTitle(arguments: Bundle?) = TITLE
@Composable
override fun Page(arguments: Bundle?) {
RegularScaffold(title = TITLE) {
- SettingsCardWithIcon()
- SettingsCardWithoutIcon()
- SampleSettingsCollapsibleCard()
- SampleSettingsCardContent()
+ SettingsBannerWithIcon()
+ SettingsBannerWithoutIcon()
+ SampleSettingsCollapsibleBanner()
+ SampleSettingsBannerContent()
}
}
@Composable
- private fun SettingsCardWithIcon() {
- SettingsCard(
- CardModel(
+ private fun SettingsBannerWithIcon() {
+ SettingsBanner(
+ BannerModel(
title = stringResource(R.string.sample_title),
text = stringResource(R.string.sample_text),
imageVector = Icons.Outlined.WarningAmber,
buttons = listOf(
- CardButton(text = "Action") {},
+ BannerButton(text = "Action") {},
),
tintColor = MaterialTheme.colorScheme.error,
containerColor = MaterialTheme.colorScheme.errorContainer,
@@ -87,11 +87,11 @@
}
@Composable
- private fun SettingsCardWithoutIcon() {
+ private fun SettingsBannerWithoutIcon() {
val sampleTitle = stringResource(R.string.sample_title)
var title by remember { mutableStateOf(sampleTitle) }
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = title,
text = stringResource(R.string.sample_text),
) { title = "Clicked" }
@@ -99,46 +99,46 @@
}
@Composable
- fun SampleSettingsCollapsibleCard() {
+ fun SampleSettingsCollapsibleBanner() {
val context = LocalContext.current
var isVisible0 by rememberSaveable { mutableStateOf(true) }
var isVisible1 by rememberSaveable { mutableStateOf(true) }
- val cards = remember {
+ val banners = remember {
mutableStateListOf(
- CardModel(
+ BannerModel(
title = context.getString(R.string.sample_title),
text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.PowerOff,
isVisible = { isVisible0 },
onDismiss = { isVisible0 = false },
buttons = listOf(
- CardButton(text = "Override") {},
- CardButton(text = "Learn more") {},
+ BannerButton(text = "Override") {},
+ BannerButton(text = "Learn more") {},
),
),
- CardModel(
+ BannerModel(
title = context.getString(R.string.sample_title),
text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.Shield,
isVisible = { isVisible1 },
onDismiss = { isVisible1 = false },
buttons = listOf(
- CardButton(text = "Action") {},
+ BannerButton(text = "Action") {},
),
)
)
}
- SettingsCollapsibleCard(
+ SettingsCollapsibleBanner(
title = "More alerts",
imageVector = Icons.Outlined.Error,
- models = cards.toList()
+ models = banners.toList()
)
}
@Composable
- fun SampleSettingsCardContent() {
- SettingsCard {
- SettingsCardContent {
+ fun SampleSettingsBannerContent() {
+ SettingsBanner {
+ SettingsBannerContent {
Box(
Modifier
.fillMaxWidth()
@@ -148,7 +148,7 @@
Text(text = "Abc")
}
}
- SettingsCardContent {
+ SettingsBannerContent {
Box(
Modifier
.fillMaxWidth()
@@ -171,13 +171,13 @@
}
}
- private const val TITLE = "Sample Card"
+ private const val TITLE = "Sample Banner"
}
@Preview
@Composable
-private fun CardPagePreview() {
+private fun BannerPagePreview() {
SettingsTheme {
- CardPageProvider.Page(null)
+ BannerPageProvider.Page(null)
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
index 654719d..b1558cc 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
@@ -28,7 +28,7 @@
import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
-import com.android.settingslib.spa.gallery.card.CardPageProvider
+import com.android.settingslib.spa.gallery.banner.BannerPageProvider
import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
@@ -73,7 +73,7 @@
ChartPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
DialogMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
EditorMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
- CardPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+ BannerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
CopyablePageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/BannerModel.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/BannerModel.kt
new file mode 100644
index 0000000..4ef258f
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/BannerModel.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.spa.widget.banner
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+
+data class BannerButton(
+ val text: String,
+ val contentDescription: String? = null,
+ val onClick: () -> Unit,
+)
+
+data class BannerModel(
+ val title: String,
+ val text: String,
+ val imageVector: ImageVector? = null,
+ val isVisible: () -> Boolean = { true },
+
+ /**
+ * A dismiss button will be displayed if this is not null.
+ *
+ * And this callback will be called when user clicks the button.
+ */
+ val onDismiss: (() -> Unit)? = null,
+
+ val buttons: List<BannerButton> = emptyList(),
+
+ /** If specified, this color will be used to tint the icon and the buttons. */
+ val tintColor: Color = Color.Unspecified,
+
+ /** If specified, this color will be used to tint the icon and the buttons. */
+ val containerColor: Color = Color.Unspecified,
+
+ val onClick: (() -> Unit)? = null,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
new file mode 100644
index 0000000..e3f4860
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 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.spa.widget.banner
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
+import androidx.compose.material.icons.outlined.WarningAmber
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.debug.UiModePreviews
+import com.android.settingslib.spa.framework.compose.contentDescription
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraLarge
+import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraSmall
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.ui.SettingsBody
+import com.android.settingslib.spa.widget.ui.SettingsTitle
+
+@Composable
+fun SettingsBanner(content: @Composable ColumnScope.() -> Unit) {
+ Card(
+ shape = CornerExtraLarge,
+ colors = CardDefaults.cardColors(
+ containerColor = Color.Transparent,
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(
+ horizontal = SettingsDimension.itemPaddingEnd,
+ vertical = SettingsDimension.itemPaddingAround,
+ ),
+ content = content,
+ )
+}
+
+@Composable
+fun SettingsBannerContent(
+ containerColor: Color = Color.Unspecified,
+ content: @Composable ColumnScope.() -> Unit,
+) {
+ Card(
+ shape = CornerExtraSmall,
+ colors = CardDefaults.cardColors(
+ containerColor = containerColor.takeOrElse { MaterialTheme.colorScheme.surface },
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 1.dp),
+ content = content,
+ )
+}
+
+@Composable
+fun SettingsBanner(model: BannerModel) {
+ SettingsBanner {
+ SettingsBannerImpl(model)
+ }
+}
+
+@Composable
+internal fun SettingsBannerImpl(model: BannerModel) {
+ AnimatedVisibility(visible = model.isVisible()) {
+ SettingsBannerContent(containerColor = model.containerColor) {
+ Column(
+ modifier = (model.onClick?.let { Modifier.clickable(onClick = it) } ?: Modifier)
+ .padding(
+ horizontal = SettingsDimension.dialogItemPaddingHorizontal,
+ vertical = SettingsDimension.itemPaddingAround,
+ ),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
+ ) {
+ BannerHeader(model.imageVector, model.tintColor, model.onDismiss)
+ SettingsTitle(model.title)
+ SettingsBody(model.text)
+ Buttons(model.buttons, model.tintColor)
+ }
+ }
+ }
+}
+
+@Composable
+fun BannerHeader(imageVector: ImageVector?, iconColor: Color, onDismiss: (() -> Unit)? = null) {
+ if (imageVector != null || onDismiss != null) {
+ Spacer(Modifier.height(SettingsDimension.buttonPaddingVertical))
+ }
+ Row(Modifier.fillMaxWidth()) {
+ BannerIcon(imageVector, iconColor)
+ Spacer(modifier = Modifier.weight(1f))
+ DismissButton(onDismiss)
+ }
+}
+
+@Composable
+private fun BannerIcon(imageVector: ImageVector?, color: Color) {
+ if (imageVector != null) {
+ Icon(
+ imageVector = imageVector,
+ contentDescription = null,
+ modifier = Modifier.size(SettingsDimension.itemIconSize),
+ tint = color.takeOrElse { MaterialTheme.colorScheme.primary },
+ )
+ }
+}
+
+@Composable
+private fun DismissButton(onDismiss: (() -> Unit)?) {
+ if (onDismiss == null) return
+ Surface(
+ shape = CircleShape,
+ color = MaterialTheme.colorScheme.secondaryContainer,
+ ) {
+ IconButton(
+ onClick = onDismiss,
+ modifier = Modifier.size(SettingsDimension.itemIconSize)
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Close,
+ contentDescription = stringResource(
+ androidx.compose.material3.R.string.m3c_snackbar_dismiss
+ ),
+ modifier = Modifier.padding(SettingsDimension.paddingSmall),
+ )
+ }
+ }
+}
+
+@OptIn(ExperimentalLayoutApi::class)
+@Composable
+private fun Buttons(buttons: List<BannerButton>, color: Color) {
+ if (buttons.isNotEmpty()) {
+ FlowRow(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(
+ space = SettingsDimension.itemPaddingEnd,
+ alignment = Alignment.End,
+ ),
+ ) {
+ for (button in buttons) {
+ Button(button, color)
+ }
+ }
+ } else {
+ Spacer(Modifier.height(SettingsDimension.itemPaddingAround))
+ }
+}
+
+@Composable
+private fun Button(button: BannerButton, color: Color) {
+ TextButton(
+ onClick = button.onClick,
+ modifier = Modifier.contentDescription(button.contentDescription),
+ ) {
+ Text(text = button.text, color = color)
+ }
+}
+
+@UiModePreviews
+@Composable
+private fun SettingsBannerPreview() {
+ SettingsTheme {
+ SettingsBanner(
+ BannerModel(
+ title = "Lorem ipsum",
+ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ imageVector = Icons.Outlined.WarningAmber,
+ buttons = listOf(
+ BannerButton(text = "Action") {},
+ )
+ )
+ )
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsCollapsibleBanner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsCollapsibleBanner.kt
new file mode 100644
index 0000000..31a1e9c
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsCollapsibleBanner.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2023 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.spa.widget.banner
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Error
+import androidx.compose.material.icons.outlined.PowerOff
+import androidx.compose.material.icons.outlined.Shield
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import com.android.settingslib.spa.debug.UiModePreviews
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.ui.ExpandIcon
+import com.android.settingslib.spa.widget.ui.SettingsDialogItem
+import com.android.settingslib.spa.widget.ui.SettingsTitleSmall
+
+@Composable
+fun SettingsCollapsibleBanner(
+ title: String,
+ imageVector: ImageVector,
+ models: List<BannerModel>,
+) {
+ var expanded by rememberSaveable { mutableStateOf(false) }
+ SettingsBanner {
+ SettingsBannerContent {
+ Header(title, imageVector, models.count { it.isVisible() }, expanded) { expanded = it }
+ }
+ AnimatedVisibility(expanded) {
+ Column {
+ for (model in models) {
+ SettingsBannerImpl(model)
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun Header(
+ title: String,
+ imageVector: ImageVector,
+ cardCount: Int,
+ expanded: Boolean,
+ setExpanded: (Boolean) -> Unit,
+) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable { setExpanded(!expanded) }
+ .padding(
+ horizontal = SettingsDimension.itemPaddingStart,
+ vertical = SettingsDimension.itemPaddingVertical,
+ ),
+ horizontalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingStart),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ imageVector = imageVector,
+ contentDescription = null,
+ modifier = Modifier.size(SettingsDimension.itemIconSize),
+ tint = MaterialTheme.colorScheme.primary,
+ )
+ Box(modifier = Modifier.weight(1f)) {
+ SettingsTitleSmall(title, useMediumWeight = true)
+ }
+ BannerCount(cardCount, expanded)
+ }
+}
+
+@Composable
+private fun BannerCount(modelSize: Int, expanded: Boolean) {
+ Surface(
+ shape = SettingsShape.CornerExtraLarge,
+ color = MaterialTheme.colorScheme.secondaryContainer,
+ ) {
+ Row(
+ modifier = Modifier.padding(SettingsDimension.paddingSmall),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Spacer(modifier = Modifier.padding(SettingsDimension.paddingSmall))
+ SettingsDialogItem(modelSize.toString())
+ ExpandIcon(expanded)
+ }
+ }
+}
+
+@UiModePreviews
+@Composable
+private fun SettingsCollapsibleBannerPreview() {
+ SettingsTheme {
+ SettingsCollapsibleBanner(
+ title = "More alerts",
+ imageVector = Icons.Outlined.Error,
+ models = listOf(
+ BannerModel(
+ title = "Lorem ipsum",
+ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ imageVector = Icons.Outlined.PowerOff,
+ buttons = listOf(
+ BannerButton(text = "Action") {},
+ )
+ ),
+ BannerModel(
+ title = "Lorem ipsum",
+ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ imageVector = Icons.Outlined.Shield,
+ buttons = listOf(
+ BannerButton(text = "Action") {},
+ )
+ )
+ )
+ )
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsBannerTest.kt
similarity index 79%
rename from packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
rename to packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsBannerTest.kt
index ffc7e86..a8479b0 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsBannerTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settingslib.spa.widget.card
+package com.android.settingslib.spa.widget.banner
import android.content.Context
import androidx.compose.runtime.getValue
@@ -35,16 +35,16 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-class SettingsCardTest {
+class SettingsBannerTest {
@get:Rule val composeTestRule = createComposeRule()
private val context: Context = ApplicationProvider.getApplicationContext()
@Test
- fun settingsCard_titleDisplayed() {
+ fun settingsBanner_titleDisplayed() {
composeTestRule.setContent {
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = TITLE,
text = "",
)
@@ -55,10 +55,10 @@
}
@Test
- fun settingsCard_textDisplayed() {
+ fun settingsBanner_textDisplayed() {
composeTestRule.setContent {
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = "",
text = TEXT,
)
@@ -69,13 +69,13 @@
}
@Test
- fun settingsCard_buttonDisplayed() {
+ fun settingsBanner_buttonDisplayed() {
composeTestRule.setContent {
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = "",
text = "",
- buttons = listOf(CardButton(text = TEXT) {}),
+ buttons = listOf(BannerButton(text = TEXT) {}),
)
)
}
@@ -84,14 +84,14 @@
}
@Test
- fun settingsCard_buttonCanBeClicked() {
+ fun settingsBanner_buttonCanBeClicked() {
var buttonClicked = false
composeTestRule.setContent {
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = "",
text = "",
- buttons = listOf(CardButton(text = TEXT) { buttonClicked = true }),
+ buttons = listOf(BannerButton(text = TEXT) { buttonClicked = true }),
)
)
}
@@ -102,13 +102,13 @@
}
@Test
- fun settingsCard_buttonHaveContentDescription() {
+ fun settingsBanner_buttonHaveContentDescription() {
composeTestRule.setContent {
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = "",
text = "",
- buttons = listOf(CardButton(
+ buttons = listOf(BannerButton(
text = TEXT,
contentDescription = CONTENT_DESCRIPTION,
) {}
@@ -121,11 +121,11 @@
}
@Test
- fun settingsCard_dismiss() {
+ fun settingsBanner_dismiss() {
composeTestRule.setContent {
var isVisible by remember { mutableStateOf(true) }
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = TITLE,
text = "",
isVisible = { isVisible },
@@ -142,11 +142,11 @@
}
@Test
- fun settingsCard_clickable() {
+ fun settingsBanner_clickable() {
var clicked by mutableStateOf(false)
composeTestRule.setContent {
- SettingsCard(
- CardModel(
+ SettingsBanner(
+ BannerModel(
title = TITLE,
text = "",
) { clicked = true }
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleBannerTest.kt
similarity index 78%
rename from packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
rename to packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleBannerTest.kt
index aba9d7b..1080fde 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleBannerTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settingslib.spa.widget.card
+package com.android.settingslib.spa.widget.banner
import android.content.Context
import androidx.compose.material.icons.Icons
@@ -36,44 +36,44 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-class SettingsCollapsibleCardTest {
+class SettingsCollapsibleBannerTest {
@get:Rule
val composeTestRule = createComposeRule()
private val context: Context = ApplicationProvider.getApplicationContext()
@Test
- fun settingsCollapsibleCard_titleDisplayed() {
+ fun settingsCollapsibleBanner_titleDisplayed() {
setContent()
composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
}
@Test
- fun settingsCollapsibleCard_cardCountDisplayed() {
+ fun settingsCollapsibleBanner_BannerCountDisplayed() {
setContent()
composeTestRule.onNodeWithText("1").assertIsDisplayed()
}
@Test
- fun settingsCollapsibleCard_initial_cardTextNotExists() {
+ fun settingsCollapsibleBanner_initial_BannerTextNotExists() {
setContent()
- composeTestRule.onNodeWithText(CARD_TEXT).assertDoesNotExist()
+ composeTestRule.onNodeWithText(Banner_TEXT).assertDoesNotExist()
}
@Test
- fun settingsCollapsibleCard_afterExpand_cardTextDisplayed() {
+ fun settingsCollapsibleBanner_afterExpand_BannerTextDisplayed() {
setContent()
composeTestRule.onNodeWithText(TITLE).performClick()
- composeTestRule.onNodeWithText(CARD_TEXT).assertIsDisplayed()
+ composeTestRule.onNodeWithText(Banner_TEXT).assertIsDisplayed()
}
@Test
- fun settingsCollapsibleCard_dismiss() {
+ fun settingsCollapsibleBanner_dismiss() {
setContent()
composeTestRule.onNodeWithText(TITLE).performClick()
@@ -81,20 +81,20 @@
context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
).performClick()
- composeTestRule.onNodeWithText(CARD_TEXT).isNotDisplayed()
+ composeTestRule.onNodeWithText(Banner_TEXT).isNotDisplayed()
composeTestRule.onNodeWithText("0").assertIsDisplayed()
}
private fun setContent() {
composeTestRule.setContent {
var isVisible by rememberSaveable { mutableStateOf(true) }
- SettingsCollapsibleCard(
+ SettingsCollapsibleBanner(
title = TITLE,
imageVector = Icons.Outlined.Error,
models = listOf(
- CardModel(
+ BannerModel(
title = "",
- text = CARD_TEXT,
+ text = Banner_TEXT,
isVisible = { isVisible },
onDismiss = { isVisible = false },
)
@@ -105,6 +105,6 @@
private companion object {
const val TITLE = "Title"
- const val CARD_TEXT = "Card Text"
+ const val Banner_TEXT = "Banner Text"
}
}
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 34b597b..79c3ff9 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -139,3 +139,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "audio_sharing_qs_dialog_improvement"
+ namespace: "cross_device_experiences"
+ description: "Gates whether to enable audio sharing qs dialog improvement"
+ bug: "360759048"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 4d771c0..feee89a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1411,6 +1411,8 @@
<string name="media_transfer_this_device_name_tablet">This tablet</string>
<!-- Name of the default media output of the TV. [CHAR LIMIT=30] -->
<string name="media_transfer_this_device_name_tv">@string/tv_media_transfer_default</string>
+ <!-- Name of the internal mic. [CHAR LIMIT=30] -->
+ <string name="media_transfer_internal_mic">Microphone (internal)</string>
<!-- Name of the dock device. [CHAR LIMIT=30] -->
<string name="media_transfer_dock_speaker_device_name">Dock speaker</string>
<!-- Default name of the external device. [CHAR LIMIT=30] -->
@@ -1637,6 +1639,12 @@
<!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=50] -->
<string name="media_transfer_wired_usb_device_name">Wired headphone</string>
+ <!-- Name of the 3.5mm audio device mic. [CHAR LIMIT=50] -->
+ <string name="media_transfer_wired_device_mic_name">Mic jack</string>
+
+ <!-- Name of the usb audio device mic. [CHAR LIMIT=50] -->
+ <string name="media_transfer_usb_device_mic_name">USB mic</string>
+
<!-- Label for Wifi hotspot switch on. Toggles hotspot on [CHAR LIMIT=30] -->
<string name="wifi_hotspot_switch_on_text">On</string>
<!-- Label for Wifi hotspot switch off. Toggles hotspot off [CHAR LIMIT=30] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 1e58335..9d56c77 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -520,8 +520,6 @@
if (android.webkit.Flags.updateServiceIpcWrapper()) {
if (pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
- // WebViewUpdateManager.getInstance() will not return null on devices with
- // FEATURE_WEBVIEW.
provider = WebViewUpdateManager.getInstance().getDefaultWebViewPackage();
}
} else {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index c6eb9fd..6dab224 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.os.Build;
@@ -356,6 +357,8 @@
final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
preferredMainDevice = deviceManager.findDevice(bluetoothDeviceOfPreferredMainDevice);
if (haveMultiMainDevicesInAllOfDevicesList) {
+ log("addMemberDevicesIntoMainDevice: haveMultiMainDevicesInAllOfDevicesList. "
+ + "Combine them and also keep the preferred main device as main device.");
// put another devices into main device.
for (CachedBluetoothDevice deviceItem : topLevelOfGroupDevicesList) {
if (deviceItem.getDevice() == null || deviceItem.getDevice().equals(
@@ -376,6 +379,7 @@
preferredMainDevice.refresh();
hasChanged = true;
}
+ syncAudioSharingSourceIfNeeded(preferredMainDevice);
}
if (hasChanged) {
log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
@@ -384,6 +388,41 @@
return hasChanged;
}
+ private void syncAudioSharingSourceIfNeeded(CachedBluetoothDevice mainDevice) {
+ boolean isAudioSharingEnabled = BluetoothUtils.isAudioSharingEnabled();
+ if (isAudioSharingEnabled) {
+ boolean hasBroadcastSource = BluetoothUtils.isBroadcasting(mBtManager)
+ && BluetoothUtils.hasConnectedBroadcastSource(
+ mainDevice, mBtManager);
+ if (hasBroadcastSource) {
+ LocalBluetoothLeBroadcast broadcast = mBtManager == null ? null
+ : mBtManager.getProfileManager().getLeAudioBroadcastProfile();
+ BluetoothLeBroadcastMetadata metadata = broadcast == null ? null :
+ broadcast.getLatestBluetoothLeBroadcastMetadata();
+ LocalBluetoothLeBroadcastAssistant assistant = mBtManager == null ? null
+ : mBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ if (metadata != null && assistant != null) {
+ log("addMemberDevicesIntoMainDevice: sync audio sharing source after "
+ + "combining the top level devices.");
+ Set<CachedBluetoothDevice> deviceSet = new HashSet<>();
+ deviceSet.add(mainDevice);
+ deviceSet.addAll(mainDevice.getMemberDevice());
+ Set<BluetoothDevice> sinksToSync = deviceSet.stream()
+ .map(CachedBluetoothDevice::getDevice)
+ .filter(device ->
+ !BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(
+ device, mBtManager))
+ .collect(Collectors.toSet());
+ for (BluetoothDevice device : sinksToSync) {
+ log("addMemberDevicesIntoMainDevice: sync audio sharing source to "
+ + device.getAnonymizedAddress());
+ assistant.addSource(device, metadata, /* isGroupOp= */ false);
+ }
+ }
+ }
+ }
+ }
+
private void log(String msg) {
if (DEBUG) {
Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
index a0fe5d2..38183d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
@@ -36,6 +36,7 @@
val className: String,
val intentAction: String,
val preferenceKey: String? = null,
+ val highlighted: Boolean = false,
val extras: Bundle = Bundle.EMPTY,
) : Parcelable {
@@ -47,6 +48,7 @@
writeString(packageName)
writeString(className)
writeString(intentAction)
+ writeBoolean(highlighted)
writeString(preferenceKey)
writeBundle(extras)
}
@@ -63,6 +65,7 @@
packageName = readString() ?: "",
className = readString() ?: "",
intentAction = readString() ?: "",
+ highlighted = readBoolean(),
preferenceKey = readString() ?: "",
extras = readBundle((Bundle::class.java.classLoader)) ?: Bundle.EMPTY,
)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
index 4b67ef7..c8c7562 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
@@ -42,6 +42,8 @@
return MultiTogglePreference.readFromParcel(in);
case DeviceSettingType.DEVICE_SETTING_TYPE_FOOTER:
return DeviceSettingFooterPreference.readFromParcel(in);
+ case DeviceSettingType.DEVICE_SETTING_TYPE_HELP:
+ return DeviceSettingHelpPreference.readFromParcel(in);
default:
return UNKNOWN;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 769b6e6..29664f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -110,15 +110,16 @@
if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
BluetoothProfilesItem(
settingId,
+ highlighted,
preferenceKey!!,
extras.getStringArrayList(DeviceSettingContract.INVISIBLE_PROFILES)
?: emptyList()
)
} else {
- CommonBuiltinItem(settingId, preferenceKey!!)
+ CommonBuiltinItem(settingId, highlighted, preferenceKey!!)
}
} else {
- AppProvidedItem(settingId)
+ AppProvidedItem(settingId, highlighted)
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
index 08fb3fb..5958c30 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
@@ -34,6 +34,7 @@
/** Models a device setting item in config. */
sealed interface DeviceSettingConfigItemModel {
@DeviceSettingId val settingId: Int
+ val highlighted: Boolean
/** A built-in item in Settings. */
sealed interface BuiltinItem : DeviceSettingConfigItemModel {
@@ -43,18 +44,22 @@
/** A general built-in item in Settings. */
data class CommonBuiltinItem(
@DeviceSettingId override val settingId: Int,
+ override val highlighted: Boolean,
override val preferenceKey: String,
) : BuiltinItem
/** A bluetooth profiles in Settings. */
data class BluetoothProfilesItem(
@DeviceSettingId override val settingId: Int,
+ override val highlighted: Boolean,
override val preferenceKey: String,
val invisibleProfiles: List<String>,
) : BuiltinItem
}
/** A remote item provided by other apps. */
- data class AppProvidedItem(@DeviceSettingId override val settingId: Int) :
- DeviceSettingConfigItemModel
+ data class AppProvidedItem(
+ @DeviceSettingId override val settingId: Int,
+ override val highlighted: Boolean,
+ ) : DeviceSettingConfigItemModel
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
deleted file mode 100644
index 7994924..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
+++ /dev/null
@@ -1,136 +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 com.android.settingslib.core.lifecycle;
-
-
-import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
-import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
-import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
-import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
-import static androidx.lifecycle.Lifecycle.Event.ON_START;
-import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
-
-import android.annotation.CallSuper;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settingslib.preference.PreferenceFragment;
-
-/**
- * Preference fragment that has hooks to observe fragment lifecycle events.
- */
-public abstract class ObservablePreferenceFragment extends PreferenceFragment
- implements LifecycleOwner {
-
- private final Lifecycle mLifecycle = new Lifecycle(this);
-
- public Lifecycle getSettingsLifecycle() {
- return mLifecycle;
- }
-
- @CallSuper
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- mLifecycle.onAttach(context);
- }
-
- @CallSuper
- @Override
- public void onCreate(Bundle savedInstanceState) {
- mLifecycle.onCreate(savedInstanceState);
- mLifecycle.handleLifecycleEvent(ON_CREATE);
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
- mLifecycle.setPreferenceScreen(preferenceScreen);
- super.setPreferenceScreen(preferenceScreen);
- }
-
- @CallSuper
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mLifecycle.onSaveInstanceState(outState);
- }
-
- @CallSuper
- @Override
- public void onStart() {
- mLifecycle.handleLifecycleEvent(ON_START);
- super.onStart();
- }
-
- @CallSuper
- @Override
- public void onResume() {
- mLifecycle.handleLifecycleEvent(ON_RESUME);
- super.onResume();
- }
-
- @CallSuper
- @Override
- public void onPause() {
- mLifecycle.handleLifecycleEvent(ON_PAUSE);
- super.onPause();
- }
-
- @CallSuper
- @Override
- public void onStop() {
- mLifecycle.handleLifecycleEvent(ON_STOP);
- super.onStop();
- }
-
- @CallSuper
- @Override
- public void onDestroy() {
- mLifecycle.handleLifecycleEvent(ON_DESTROY);
- super.onDestroy();
- }
-
- @CallSuper
- @Override
- public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- mLifecycle.onCreateOptionsMenu(menu, inflater);
- super.onCreateOptionsMenu(menu, inflater);
- }
-
- @CallSuper
- @Override
- public void onPrepareOptionsMenu(final Menu menu) {
- mLifecycle.onPrepareOptionsMenu(menu);
- super.onPrepareOptionsMenu(menu);
- }
-
- @CallSuper
- @Override
- public boolean onOptionsItemSelected(final MenuItem menuItem) {
- boolean lifecycleHandled = mLifecycle.onOptionsItemSelected(menuItem);
- if (!lifecycleHandled) {
- return super.onOptionsItemSelected(menuItem);
- }
- return lifecycleHandled;
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
new file mode 100644
index 0000000..766cd43
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2024 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.media;
+
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY;
+import static android.media.AudioDeviceInfo.TYPE_USB_DEVICE;
+import static android.media.AudioDeviceInfo.TYPE_USB_HEADSET;
+import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET;
+
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.media.AudioDeviceInfo.AudioDeviceType;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settingslib.R;
+
+/** {@link MediaDevice} implementation that represents an input device. */
+public class InputMediaDevice extends MediaDevice {
+
+ private static final String TAG = "InputMediaDevice";
+
+ private final String mId;
+
+ private final @AudioDeviceType int mAudioDeviceInfoType;
+
+ private final int mMaxVolume;
+
+ private final int mCurrentVolume;
+
+ private final boolean mIsVolumeFixed;
+
+ private InputMediaDevice(
+ @NonNull Context context,
+ @NonNull String id,
+ @AudioDeviceType int audioDeviceInfoType,
+ int maxVolume,
+ int currentVolume,
+ boolean isVolumeFixed) {
+ super(context, /* info= */ null, /* item= */ null);
+ mId = id;
+ mAudioDeviceInfoType = audioDeviceInfoType;
+ mMaxVolume = maxVolume;
+ mCurrentVolume = currentVolume;
+ mIsVolumeFixed = isVolumeFixed;
+ initDeviceRecord();
+ }
+
+ @Nullable
+ public static InputMediaDevice create(
+ @NonNull Context context,
+ @NonNull String id,
+ @AudioDeviceType int audioDeviceInfoType,
+ int maxVolume,
+ int currentVolume,
+ boolean isVolumeFixed) {
+ if (!isSupportedInputDevice(audioDeviceInfoType)) {
+ return null;
+ }
+
+ return new InputMediaDevice(
+ context, id, audioDeviceInfoType, maxVolume, currentVolume, isVolumeFixed);
+ }
+
+ public static boolean isSupportedInputDevice(@AudioDeviceType int audioDeviceInfoType) {
+ return switch (audioDeviceInfoType) {
+ case TYPE_BUILTIN_MIC,
+ TYPE_WIRED_HEADSET,
+ TYPE_USB_DEVICE,
+ TYPE_USB_HEADSET,
+ TYPE_USB_ACCESSORY ->
+ true;
+ default -> false;
+ };
+ }
+
+ @Override
+ public @NonNull String getName() {
+ CharSequence name =
+ switch (mAudioDeviceInfoType) {
+ case TYPE_WIRED_HEADSET ->
+ mContext.getString(R.string.media_transfer_wired_device_mic_name);
+ case TYPE_USB_DEVICE, TYPE_USB_HEADSET, TYPE_USB_ACCESSORY ->
+ mContext.getString(R.string.media_transfer_usb_device_mic_name);
+ default -> mContext.getString(R.string.media_transfer_internal_mic);
+ };
+ return name.toString();
+ }
+
+ @Override
+ public @SelectionBehavior int getSelectionBehavior() {
+ // We don't allow apps to override the selection behavior of system routes.
+ return SELECTION_BEHAVIOR_TRANSFER;
+ }
+
+ @Override
+ public @NonNull String getSummary() {
+ return "";
+ }
+
+ @Override
+ public @Nullable Drawable getIcon() {
+ return getIconWithoutBackground();
+ }
+
+ @Override
+ public @Nullable Drawable getIconWithoutBackground() {
+ return mContext.getDrawable(getDrawableResId());
+ }
+
+ @VisibleForTesting
+ int getDrawableResId() {
+ // TODO(b/357122624): check with UX to obtain the icon for desktop devices.
+ return R.drawable.ic_media_tablet;
+ }
+
+ @Override
+ public @NonNull String getId() {
+ return mId;
+ }
+
+ @Override
+ public boolean isConnected() {
+ // Indicating if the device is connected and thus showing the status of STATE_CONNECTED.
+ // Upon creation, this device is already connected.
+ return true;
+ }
+
+ @Override
+ public int getMaxVolume() {
+ return mMaxVolume;
+ }
+
+ @Override
+ public int getCurrentVolume() {
+ return mCurrentVolume;
+ }
+
+ @Override
+ public boolean isVolumeFixed() {
+ return mIsVolumeFixed;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
new file mode 100644
index 0000000..548eb3f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2024 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.media;
+
+import android.content.Context;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.os.Handler;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/** Provides functionalities to get/observe input routes, control input routing and volume gain. */
+public final class InputRouteManager {
+
+ private static final String TAG = "InputRouteManager";
+
+ private final Context mContext;
+
+ private final AudioManager mAudioManager;
+
+ @VisibleForTesting final List<MediaDevice> mInputMediaDevices = new CopyOnWriteArrayList<>();
+
+ private final Collection<InputDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
+
+ @VisibleForTesting
+ final AudioDeviceCallback mAudioDeviceCallback =
+ new AudioDeviceCallback() {
+ @Override
+ public void onAudioDevicesAdded(@NonNull AudioDeviceInfo[] addedDevices) {
+ dispatchInputDeviceListUpdate();
+ }
+
+ @Override
+ public void onAudioDevicesRemoved(@NonNull AudioDeviceInfo[] removedDevices) {
+ dispatchInputDeviceListUpdate();
+ }
+ };
+
+ /* package */ InputRouteManager(@NonNull Context context, @NonNull AudioManager audioManager) {
+ mContext = context;
+ mAudioManager = audioManager;
+ Handler handler = new Handler(context.getMainLooper());
+
+ mAudioManager.registerAudioDeviceCallback(mAudioDeviceCallback, handler);
+ }
+
+ public void registerCallback(@NonNull InputDeviceCallback callback) {
+ if (!mCallbacks.contains(callback)) {
+ mCallbacks.add(callback);
+ dispatchInputDeviceListUpdate();
+ }
+ }
+
+ public void unregisterCallback(@NonNull InputDeviceCallback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ private void dispatchInputDeviceListUpdate() {
+ // TODO (b/360175574): Get selected input device.
+
+ // Get all input devices.
+ AudioDeviceInfo[] audioDeviceInfos =
+ mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+ mInputMediaDevices.clear();
+ for (AudioDeviceInfo info : audioDeviceInfos) {
+ MediaDevice mediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(info.getId()),
+ info.getType(),
+ getMaxInputGain(),
+ getCurrentInputGain(),
+ isInputGainFixed());
+ if (mediaDevice != null) {
+ mInputMediaDevices.add(mediaDevice);
+ }
+ }
+
+ final List<MediaDevice> inputMediaDevices = new ArrayList<>(mInputMediaDevices);
+ for (InputDeviceCallback callback : mCallbacks) {
+ callback.onInputDeviceListUpdated(inputMediaDevices);
+ }
+ }
+
+ public int getMaxInputGain() {
+ // TODO (b/357123335): use real input gain implementation.
+ // Using 15 for now since it matches the max index for output.
+ return 15;
+ }
+
+ public int getCurrentInputGain() {
+ // TODO (b/357123335): use real input gain implementation.
+ return 8;
+ }
+
+ public boolean isInputGainFixed() {
+ // TODO (b/357123335): use real input gain implementation.
+ return true;
+ }
+
+ /** Callback for listening to input device changes. */
+ public interface InputDeviceCallback {
+ void onInputDeviceListUpdated(@NonNull List<MediaDevice> devices);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
index 7467ee1..d58add4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
@@ -2,7 +2,6 @@
ethibodeau@google.com
michaelmikhil@google.com
apotapov@google.com
-shaoweishen@google.com
#Android Media - For minor changes and renames only.
aquilescanta@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 7b2a284..3cc111f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -140,7 +140,7 @@
private static Status computeStatus(@NonNull ZenModeConfig.ZenRule zenRuleExtraData) {
if (zenRuleExtraData.enabled) {
- if (zenRuleExtraData.isAutomaticActive()) {
+ if (zenRuleExtraData.isActive()) {
return Status.ENABLED_AND_ACTIVE;
} else {
return Status.ENABLED;
@@ -241,10 +241,6 @@
formattedTime);
}
}
- // TODO: b/333527800 - For TYPE_SCHEDULE_TIME rules we could do the same; however
- // according to the snoozing discussions the mode may or may not end at the scheduled
- // time if manually activated. When we resolve that point, we could calculate end time
- // for these modes as well.
return getTriggerDescription();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
index 698eb81..b180b69 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
@@ -18,31 +18,51 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
+import android.os.Looper;
import android.os.Parcel;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.settingslib.flags.Flags;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import com.google.common.collect.ImmutableList;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
public class CsipDeviceManagerTest {
private final static String DEVICE_NAME_1 = "TestName_1";
private final static String DEVICE_NAME_2 = "TestName_2";
@@ -59,6 +79,9 @@
private final BluetoothClass DEVICE_CLASS_2 =
createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@Mock
@@ -77,7 +100,12 @@
private A2dpProfile mA2dpProfile;
@Mock
private LeAudioProfile mLeAudioProfile;
+ @Mock
+ private LocalBluetoothLeBroadcast mBroadcast;
+ @Mock
+ private LocalBluetoothLeBroadcastAssistant mAssistant;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private CachedBluetoothDevice mCachedDevice1;
private CachedBluetoothDevice mCachedDevice2;
private CachedBluetoothDevice mCachedDevice3;
@@ -101,6 +129,12 @@
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ mShadowBluetoothAdapter.setEnabled(true);
+ mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+ BluetoothStatusCodes.FEATURE_SUPPORTED);
+ mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
+ BluetoothStatusCodes.FEATURE_SUPPORTED);
when(mDevice1.getAddress()).thenReturn(DEVICE_ADDRESS_1);
when(mDevice2.getAddress()).thenReturn(DEVICE_ADDRESS_2);
when(mDevice3.getAddress()).thenReturn(DEVICE_ADDRESS_3);
@@ -124,6 +158,8 @@
when(mLocalProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mLocalProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
+ when(mLocalProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
+ when(mLocalProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
when(mLeAudioProfile.getConnectedGroupLeadDevice(anyInt())).thenReturn(null);
mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager);
@@ -307,6 +343,7 @@
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -314,6 +351,36 @@
assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
+ verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+ any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+ }
+
+ @Test
+ public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncSource() {
+ // Condition: The preferredDevice is main and there is another main device in top list
+ // Expected Result: return true and there is the preferredDevice in top list
+ CachedBluetoothDevice preferredDevice = mCachedDevice1;
+ mCachedDevice1.getMemberDevice().clear();
+ mCachedDevices.clear();
+ mCachedDevices.add(preferredDevice);
+ mCachedDevices.add(mCachedDevice2);
+ mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
+ when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+ BluetoothLeBroadcastReceiveState state = Mockito.mock(
+ BluetoothLeBroadcastReceiveState.class);
+ when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+ when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
+
+ assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
+ .isTrue();
+ assertThat(mCachedDevices.contains(preferredDevice)).isTrue();
+ assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
+ assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
+ assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
+ verify(mAssistant).addSource(mDevice1, metadata, /* isGroupOp= */ false);
}
@Test
@@ -341,6 +408,8 @@
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
mCachedDevice3.setGroupId(GROUP1);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ when(mBroadcast.isEnabled(null)).thenReturn(false);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -351,8 +420,40 @@
assertThat(mCachedDevices.contains(mCachedDevice3)).isFalse();
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice2);
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice3);
+ assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
+ verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+ any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+ }
+
+ @Test
+ public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncSource() {
+ // Condition: The preferredDevice is member and there are two main device in top list
+ // Expected Result: return true and there is the preferredDevice in top list
+ CachedBluetoothDevice preferredDevice = mCachedDevice2;
+ BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
+ mCachedDevice3.setGroupId(GROUP1);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
+ when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+ BluetoothLeBroadcastReceiveState state = Mockito.mock(
+ BluetoothLeBroadcastReceiveState.class);
+ when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+ when(mAssistant.getAllSources(mDevice1)).thenReturn(ImmutableList.of(state));
+
+ assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
+ .isTrue();
+ shadowOf(Looper.getMainLooper()).idle();
+ // expected main is mCachedDevice1 which is the main of preferredDevice, since system
+ // switch the relationship between preferredDevice and the main of preferredDevice
+ assertThat(mCachedDevices.contains(mCachedDevice1)).isTrue();
+ assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
+ assertThat(mCachedDevices.contains(mCachedDevice3)).isFalse();
+ assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice2);
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice3);
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
+ verify(mAssistant).addSource(mDevice2, metadata, /* isGroupOp= */ false);
+ verify(mAssistant).addSource(mDevice3, metadata, /* isGroupOp= */ false);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
index 56e9b6c..86071bb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
@@ -34,6 +34,8 @@
packageName = "package_name",
className = "class_name",
intentAction = "intent_action",
+ preferenceKey = "key1",
+ highlighted = true,
extras = Bundle().apply { putString("key1", "value1") },
)
@@ -43,6 +45,7 @@
assertThat(fromParcel.packageName).isEqualTo(item.packageName)
assertThat(fromParcel.className).isEqualTo(item.className)
assertThat(fromParcel.intentAction).isEqualTo(item.intentAction)
+ assertThat(fromParcel.preferenceKey).isEqualTo(item.preferenceKey)
assertThat(fromParcel.extras.getString("key1")).isEqualTo(item.extras.getString("key1"))
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
index a0a2658..7f17293 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
@@ -33,30 +33,33 @@
mainContentItems =
listOf(
DeviceSettingItem(
- 1,
- "package_name_1",
- "class_name_1",
- "intent_action_1",
- null,
- Bundle(),
+ settingId = 1,
+ packageName = "package_name_1",
+ className = "class_name_1",
+ intentAction = "intent_action_1",
+ preferenceKey = null,
+ highlighted = false,
+ extras = Bundle(),
)),
moreSettingsItems =
listOf(
DeviceSettingItem(
- 2,
- "package_name_2",
- "class_name_2",
- "intent_action_2",
- null,
- Bundle(),
+ settingId = 2,
+ packageName = "package_name_2",
+ className = "class_name_2",
+ intentAction = "intent_action_2",
+ preferenceKey = null,
+ highlighted = false,
+ extras = Bundle(),
)),
moreSettingsHelpItem = DeviceSettingItem(
- 3,
- "package_name_2",
- "class_name_2",
- "intent_action_2",
- null,
- Bundle(),
+ settingId = 3,
+ packageName = "package_name_2",
+ className = "class_name_2",
+ intentAction = "intent_action_2",
+ preferenceKey = null,
+ highlighted = false,
+ extras = Bundle(),
),
extras = Bundle().apply { putString("key1", "value1") },
)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
new file mode 100644
index 0000000..bc1ea6c
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2024 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.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.settingslib.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class InputMediaDeviceTest {
+
+ private final int BUILTIN_MIC_ID = 1;
+ private final int WIRED_HEADSET_ID = 2;
+ private final int USB_HEADSET_ID = 3;
+ private final int MAX_VOLUME = 1;
+ private final int CURRENT_VOLUME = 0;
+ private final boolean IS_VOLUME_FIXED = true;
+
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ }
+
+ @Test
+ public void getDrawableResId_returnCorrectResId() {
+ InputMediaDevice builtinMediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(BUILTIN_MIC_ID),
+ AudioDeviceInfo.TYPE_BUILTIN_MIC,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED);
+ assertThat(builtinMediaDevice).isNotNull();
+ assertThat(builtinMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_tablet);
+ }
+
+ @Test
+ public void getName_returnCorrectName_builtinMic() {
+ InputMediaDevice builtinMediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(BUILTIN_MIC_ID),
+ AudioDeviceInfo.TYPE_BUILTIN_MIC,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED);
+ assertThat(builtinMediaDevice).isNotNull();
+ assertThat(builtinMediaDevice.getName())
+ .isEqualTo(mContext.getString(R.string.media_transfer_internal_mic));
+ }
+
+ @Test
+ public void getName_returnCorrectName_wiredHeadset() {
+ InputMediaDevice wiredMediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(WIRED_HEADSET_ID),
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED);
+ assertThat(wiredMediaDevice).isNotNull();
+ assertThat(wiredMediaDevice.getName())
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_device_mic_name));
+ }
+
+ @Test
+ public void getName_returnCorrectName_usbHeadset() {
+ InputMediaDevice usbMediaDevice =
+ InputMediaDevice.create(
+ mContext,
+ String.valueOf(USB_HEADSET_ID),
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED);
+ assertThat(usbMediaDevice).isNotNull();
+ assertThat(usbMediaDevice.getName())
+ .isEqualTo(mContext.getString(R.string.media_transfer_usb_device_mic_name));
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
new file mode 100644
index 0000000..2501ae6
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2024 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.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+
+import com.android.settingslib.testutils.shadow.ShadowRouter2Manager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowRouter2Manager.class})
+public class InputRouteManagerTest {
+ private static final int BUILTIN_MIC_ID = 1;
+ private static final int INPUT_WIRED_HEADSET_ID = 2;
+ private static final int INPUT_USB_DEVICE_ID = 3;
+ private static final int INPUT_USB_HEADSET_ID = 4;
+ private static final int INPUT_USB_ACCESSORY_ID = 5;
+
+ private final Context mContext = spy(RuntimeEnvironment.application);
+ private InputRouteManager mInputRouteManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ final AudioManager audioManager = mock(AudioManager.class);
+ mInputRouteManager = new InputRouteManager(mContext, audioManager);
+ }
+
+ @Test
+ public void onAudioDevicesAdded_shouldUpdateInputMediaDevice() {
+ final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
+ when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+ when(info1.getId()).thenReturn(BUILTIN_MIC_ID);
+
+ final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
+ when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ when(info2.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+
+ final AudioDeviceInfo info3 = mock(AudioDeviceInfo.class);
+ when(info3.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_DEVICE);
+ when(info3.getId()).thenReturn(INPUT_USB_DEVICE_ID);
+
+ final AudioDeviceInfo info4 = mock(AudioDeviceInfo.class);
+ when(info4.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_HEADSET);
+ when(info4.getId()).thenReturn(INPUT_USB_HEADSET_ID);
+
+ final AudioDeviceInfo info5 = mock(AudioDeviceInfo.class);
+ when(info5.getType()).thenReturn(AudioDeviceInfo.TYPE_USB_ACCESSORY);
+ when(info5.getId()).thenReturn(INPUT_USB_ACCESSORY_ID);
+
+ final AudioDeviceInfo unsupportedInfo = mock(AudioDeviceInfo.class);
+ when(unsupportedInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_HDMI);
+
+ final AudioManager audioManager = mock(AudioManager.class);
+ AudioDeviceInfo[] devices = {info1, info2, info3, info4, info5, unsupportedInfo};
+ when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
+
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+
+ assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
+
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+
+ // The unsupported info should be filtered out.
+ assertThat(inputRouteManager.mInputMediaDevices).hasSize(devices.length - 1);
+ assertThat(inputRouteManager.mInputMediaDevices.get(0).getId())
+ .isEqualTo(String.valueOf(BUILTIN_MIC_ID));
+ assertThat(inputRouteManager.mInputMediaDevices.get(1).getId())
+ .isEqualTo(String.valueOf(INPUT_WIRED_HEADSET_ID));
+ assertThat(inputRouteManager.mInputMediaDevices.get(2).getId())
+ .isEqualTo(String.valueOf(INPUT_USB_DEVICE_ID));
+ assertThat(inputRouteManager.mInputMediaDevices.get(3).getId())
+ .isEqualTo(String.valueOf(INPUT_USB_HEADSET_ID));
+ assertThat(inputRouteManager.mInputMediaDevices.get(4).getId())
+ .isEqualTo(String.valueOf(INPUT_USB_ACCESSORY_ID));
+ }
+
+ @Test
+ public void onAudioDevicesRemoved_shouldUpdateInputMediaDevice() {
+ final AudioManager audioManager = mock(AudioManager.class);
+ when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
+ .thenReturn(new AudioDeviceInfo[] {});
+
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+
+ final MediaDevice device = mock(MediaDevice.class);
+ inputRouteManager.mInputMediaDevices.add(device);
+
+ final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
+ when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[] {info});
+
+ assertThat(inputRouteManager.mInputMediaDevices).isEmpty();
+ }
+
+ @Test
+ public void getMaxInputGain_returnMaxInputGain() {
+ assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(15);
+ }
+
+ @Test
+ public void getCurrentInputGain_returnCurrentInputGain() {
+ assertThat(mInputRouteManager.getCurrentInputGain()).isEqualTo(8);
+ }
+
+ @Test
+ public void isInputGainFixed() {
+ assertThat(mInputRouteManager.isInputGainFixed()).isTrue();
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
index 62401a1..aca26ec 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
+++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
@@ -91,3 +91,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "support_local_overrides_sysprops"
+ namespace: "core_experiments_team_internal"
+ description: "When DeviceConfig overrides are deleted, delete new storage overrides too."
+ bug: "366022906"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index d39b564..b491b5a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -223,6 +223,7 @@
Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
Settings.Global.ENABLE_DISKSTATS_LOGGING,
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+ Settings.Global.ENABLE_USE_APP_INFO_NOT_LAUNCHED,
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
diff --git a/packages/Shell/tests/Android.bp b/packages/Shell/tests/Android.bp
index 6399ffd..082a589 100644
--- a/packages/Shell/tests/Android.bp
+++ b/packages/Shell/tests/Android.bp
@@ -26,3 +26,10 @@
instrumentation_for: "Shell",
certificate: "platform",
}
+
+test_module_config {
+ name: "ShellTests_android_server_os",
+ base: "ShellTests",
+ test_suites: ["device-tests"],
+ exclude_annotations: ["androidx.test.filters.LargeTest"],
+}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index be4e9a1..f59eab0 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -934,9 +934,9 @@
"androidx.compose.runtime_runtime",
],
libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
"truth",
],
diff --git a/packages/SystemUI/animation/lib/Android.bp b/packages/SystemUI/animation/lib/Android.bp
new file mode 100644
index 0000000..4324d463
--- /dev/null
+++ b/packages/SystemUI/animation/lib/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2024 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 {
+ default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "PlatformAnimationLib-server",
+ srcs: [
+ "src/com/android/systemui/animation/server/*.java",
+ ":PlatformAnimationLib-aidl",
+ ],
+ static_libs: [
+ "WindowManager-Shell-shared",
+ ],
+}
+
+filegroup {
+ name: "PlatformAnimationLib-aidl",
+ srcs: [
+ "src/**/*.aidl",
+ ],
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
new file mode 100644
index 0000000..3cbb688
--- /dev/null
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.server;
+
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.SurfaceControl;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
+import android.window.TransitionFilter;
+import android.window.TransitionInfo;
+import android.window.TransitionInfo.Change;
+import android.window.WindowAnimationState;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.systemui.animation.shared.IOriginTransitions;
+import com.android.wm.shell.shared.ShellTransitions;
+import com.android.wm.shell.shared.TransitionUtil;
+
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Predicate;
+
+/** An implementation of the {@link IOriginTransitions}. */
+public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
+ private static final boolean DEBUG = true;
+ private static final String TAG = "OriginTransitions";
+
+ private final Object mLock = new Object();
+ private final ShellTransitions mShellTransitions;
+ private final Context mContext;
+
+ @GuardedBy("mLock")
+ private final Map<IBinder, OriginTransitionRecord> mRecords = new ArrayMap<>();
+
+ public IOriginTransitionsImpl(Context context, ShellTransitions shellTransitions) {
+ mShellTransitions = shellTransitions;
+ mContext = context;
+ }
+
+ @Override
+ public RemoteTransition makeOriginTransition(
+ RemoteTransition launchTransition, RemoteTransition returnTransition)
+ throws RemoteException {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "makeOriginTransition: (" + launchTransition + ", " + returnTransition + ")");
+ }
+ enforceRemoteTransitionPermission();
+ synchronized (mLock) {
+ OriginTransitionRecord record =
+ new OriginTransitionRecord(launchTransition, returnTransition);
+ mRecords.put(record.getToken(), record);
+ return record.asLaunchableTransition();
+ }
+ }
+
+ @Override
+ public void cancelOriginTransition(RemoteTransition originTransition) {
+ if (DEBUG) {
+ Log.d(TAG, "cancelOriginTransition: " + originTransition);
+ }
+ enforceRemoteTransitionPermission();
+ synchronized (mLock) {
+ if (!mRecords.containsKey(originTransition.asBinder())) {
+ return;
+ }
+ mRecords.get(originTransition.asBinder()).destroy();
+ }
+ }
+
+ private void enforceRemoteTransitionPermission() {
+ mContext.enforceCallingPermission(
+ Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ "Missing permission "
+ + Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS);
+ }
+
+ public void dump(IndentingPrintWriter ipw) {
+ ipw.println("IOriginTransitionsImpl");
+ ipw.println("Active records:");
+ ipw.increaseIndent();
+ synchronized (mLock) {
+ if (mRecords.isEmpty()) {
+ ipw.println("none");
+ } else {
+ for (OriginTransitionRecord record : mRecords.values()) {
+ record.dump(ipw);
+ }
+ }
+ }
+ ipw.decreaseIndent();
+ }
+
+ /**
+ * An {@link IRemoteTransition} that delegates animation to another {@link IRemoteTransition}
+ * and notify callbacks when the transition starts.
+ */
+ private static class RemoteTransitionDelegate extends IRemoteTransition.Stub {
+ private final IRemoteTransition mTransition;
+ private final Predicate<TransitionInfo> mOnStarting;
+ private final Executor mExecutor;
+
+ RemoteTransitionDelegate(
+ Executor executor,
+ IRemoteTransition transition,
+ Predicate<TransitionInfo> onStarting) {
+ mExecutor = executor;
+ mTransition = transition;
+ mOnStarting = onStarting;
+ }
+
+ @Override
+ public void startAnimation(
+ IBinder token,
+ TransitionInfo info,
+ SurfaceControl.Transaction t,
+ IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ if (DEBUG) {
+ Log.d(TAG, "startAnimation: " + info);
+ }
+ if (!mOnStarting.test(info)) {
+ Log.w(TAG, "Skipping cancelled transition " + mTransition);
+ t.addTransactionCommittedListener(
+ mExecutor,
+ () -> {
+ try {
+ finishCallback.onTransitionFinished(null, null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to report finish.", e);
+ }
+ })
+ .apply();
+ return;
+ }
+ mTransition.startAnimation(token, info, t, finishCallback);
+ }
+
+ @Override
+ public void mergeAnimation(
+ IBinder transition,
+ TransitionInfo info,
+ SurfaceControl.Transaction t,
+ IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ if (DEBUG) {
+ Log.d(TAG, "mergeAnimation: " + info);
+ }
+ mTransition.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ }
+
+ @Override
+ public void takeOverAnimation(
+ IBinder transition,
+ TransitionInfo info,
+ SurfaceControl.Transaction t,
+ IRemoteTransitionFinishedCallback finishCallback,
+ WindowAnimationState[] states)
+ throws RemoteException {
+ if (DEBUG) {
+ Log.d(TAG, "takeOverAnimation: " + info);
+ }
+ mTransition.takeOverAnimation(transition, info, t, finishCallback, states);
+ }
+
+ @Override
+ public void onTransitionConsumed(IBinder transition, boolean aborted)
+ throws RemoteException {
+ if (DEBUG) {
+ Log.d(TAG, "onTransitionConsumed: aborted=" + aborted);
+ }
+ mTransition.onTransitionConsumed(transition, aborted);
+ }
+
+ @Override
+ public String toString() {
+ return "RemoteTransitionDelegate{transition=" + mTransition + "}";
+ }
+ }
+
+ /** A data record containing the origin transition pieces. */
+ private class OriginTransitionRecord implements IBinder.DeathRecipient {
+ private final RemoteTransition mWrappedLaunchTransition;
+ private final RemoteTransition mWrappedReturnTransition;
+
+ @GuardedBy("mLock")
+ private boolean mDestroyed;
+
+ OriginTransitionRecord(RemoteTransition launchTransition, RemoteTransition returnTransition)
+ throws RemoteException {
+ mWrappedLaunchTransition = wrap(launchTransition, this::onLaunchTransitionStarting);
+ mWrappedReturnTransition = wrap(returnTransition, this::onReturnTransitionStarting);
+ linkToDeath();
+ }
+
+ private boolean onLaunchTransitionStarting(TransitionInfo info) {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return false;
+ }
+ TransitionFilter filter = createFilterForReverseTransition(info);
+ if (filter != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Registering filter " + filter);
+ }
+ mShellTransitions.registerRemote(filter, mWrappedReturnTransition);
+ }
+ return true;
+ }
+ }
+
+ private boolean onReturnTransitionStarting(TransitionInfo info) {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return false;
+ }
+ // Clean up stuff.
+ destroy();
+ return true;
+ }
+ }
+
+ public void destroy() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ // Already destroyed.
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Destroying origin transition record " + this);
+ }
+ mDestroyed = true;
+ unlinkToDeath();
+ mShellTransitions.unregisterRemote(mWrappedReturnTransition);
+ mRecords.remove(getToken());
+ }
+ }
+
+ private void linkToDeath() throws RemoteException {
+ asDelegate(mWrappedLaunchTransition).mTransition.asBinder().linkToDeath(this, 0);
+ asDelegate(mWrappedReturnTransition).mTransition.asBinder().linkToDeath(this, 0);
+ }
+
+ private void unlinkToDeath() {
+ asDelegate(mWrappedLaunchTransition).mTransition.asBinder().unlinkToDeath(this, 0);
+ asDelegate(mWrappedReturnTransition).mTransition.asBinder().unlinkToDeath(this, 0);
+ }
+
+ public IBinder getToken() {
+ return asLaunchableTransition().asBinder();
+ }
+
+ public RemoteTransition asLaunchableTransition() {
+ return mWrappedLaunchTransition;
+ }
+
+ @Override
+ public void binderDied() {
+ destroy();
+ }
+
+ @Override
+ public String toString() {
+ return "OriginTransitionRecord{launch="
+ + mWrappedReturnTransition
+ + ", return="
+ + mWrappedReturnTransition
+ + "}";
+ }
+
+ public void dump(IndentingPrintWriter ipw) {
+ synchronized (mLock) {
+ ipw.println("OriginTransitionRecord");
+ ipw.increaseIndent();
+ ipw.println("mDestroyed: " + mDestroyed);
+ ipw.println("Launch transition:");
+ ipw.increaseIndent();
+ ipw.println(mWrappedLaunchTransition);
+ ipw.decreaseIndent();
+ ipw.println("Return transition:");
+ ipw.increaseIndent();
+ ipw.println(mWrappedReturnTransition);
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ }
+ }
+
+ private static RemoteTransitionDelegate asDelegate(RemoteTransition transition) {
+ return (RemoteTransitionDelegate) transition.getRemoteTransition();
+ }
+
+ private RemoteTransition wrap(
+ RemoteTransition transition, Predicate<TransitionInfo> onStarting) {
+ return new RemoteTransition(
+ new RemoteTransitionDelegate(
+ mContext.getMainExecutor(),
+ transition.getRemoteTransition(),
+ onStarting),
+ transition.getDebugName());
+ }
+
+ @Nullable
+ private static TransitionFilter createFilterForReverseTransition(TransitionInfo info) {
+ TaskInfo launchingTaskInfo = null;
+ TaskInfo launchedTaskInfo = null;
+ ComponentName launchingActivity = null;
+ ComponentName launchedActivity = null;
+ for (Change change : info.getChanges()) {
+ int mode = change.getMode();
+ TaskInfo taskInfo = change.getTaskInfo();
+ ComponentName activity = change.getActivityComponent();
+ if (TransitionUtil.isClosingMode(mode)
+ && launchingTaskInfo == null
+ && taskInfo != null) {
+ // Found the launching task!
+ launchingTaskInfo = taskInfo;
+ } else if (TransitionUtil.isOpeningMode(mode)
+ && launchedTaskInfo == null
+ && taskInfo != null) {
+ // Found the launched task!
+ launchedTaskInfo = taskInfo;
+ } else if (TransitionUtil.isClosingMode(mode)
+ && launchingActivity == null
+ && activity != null) {
+ // Found the launching activity
+ launchingActivity = activity;
+ } else if (TransitionUtil.isOpeningMode(mode)
+ && launchedActivity == null
+ && activity != null) {
+ // Found the launched activity!
+ launchedActivity = activity;
+ }
+ }
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "createFilterForReverseTransition: launchingTaskInfo="
+ + launchingTaskInfo
+ + ", launchedTaskInfo="
+ + launchedTaskInfo
+ + ", launchingActivity="
+ + launchedActivity
+ + ", launchedActivity="
+ + launchedActivity);
+ }
+ if (launchingTaskInfo == null && launchingActivity == null) {
+ Log.w(
+ TAG,
+ "createFilterForReverseTransition: unable to find launching task or"
+ + " launching activity!");
+ return null;
+ }
+ if (launchedTaskInfo == null && launchedActivity == null) {
+ Log.w(
+ TAG,
+ "createFilterForReverseTransition: unable to find launched task or launched"
+ + " activity!");
+ return null;
+ }
+ if (launchedTaskInfo != null && launchedTaskInfo.launchCookies.isEmpty()) {
+ Log.w(
+ TAG,
+ "createFilterForReverseTransition: skipped - launched task has no launch"
+ + " cookie!");
+ return null;
+ }
+ TransitionFilter filter = new TransitionFilter();
+ filter.mTypeSet = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+
+ // The opening activity of the return transition must match the activity we just closed.
+ TransitionFilter.Requirement req1 = new TransitionFilter.Requirement();
+ req1.mModes = new int[] {TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ req1.mTopActivity =
+ launchingActivity == null ? launchingTaskInfo.topActivity : launchingActivity;
+
+ TransitionFilter.Requirement req2 = new TransitionFilter.Requirement();
+ req2.mModes = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ if (launchedTaskInfo != null) {
+ // For task transitions, the closing task's cookie must match the task we just
+ // launched.
+ req2.mLaunchCookie = launchedTaskInfo.launchCookies.get(0);
+ } else {
+ // For activity transitions, the closing activity of the return transition must
+ // match
+ // the activity we just launched.
+ req2.mTopActivity = launchedActivity;
+ }
+
+ filter.mRequirements = new TransitionFilter.Requirement[] {req1, req2};
+ return filter;
+ }
+ }
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/shared/IOriginTransitions.aidl b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/shared/IOriginTransitions.aidl
new file mode 100644
index 0000000..31cca70
--- /dev/null
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/shared/IOriginTransitions.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.shared;
+
+import android.window.RemoteTransition;
+
+/**
+ * An interface for an app to link a launch transition and a return transition together into an
+ * origin transition.
+ */
+interface IOriginTransitions {
+
+ /**
+ * Create a new "origin transition" which wraps a launch transition and a return transition.
+ * The returned {@link RemoteTransition} is expected to be passed to
+ * {@link ActivityOptions#makeRemoteTransition(RemoteTransition)} to create an
+ * {@link ActivityOptions} and being used to launch an intent. When being used with
+ * {@link ActivityOptions}, the launch transition will be triggered for launching the intent,
+ * and the return transition will be remembered and triggered for returning from the launched
+ * activity.
+ */
+ RemoteTransition makeOriginTransition(in RemoteTransition launchTransition,
+ in RemoteTransition returnTransition) = 1;
+
+ /**
+ * Cancels an origin transition. Any parts not yet played will no longer be triggered, and the
+ * origin transition object will reset to a single frame animation.
+ */
+ void cancelOriginTransition(in RemoteTransition originTransition) = 2;
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index c14ee62..9d0b095 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -55,6 +55,7 @@
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.Flags.activityTransitionUseLargestWindow
import com.android.systemui.Flags.translucentOccludingActivityFix
+import com.android.systemui.animation.TransitionAnimator.Companion.toTransitionState
import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
import com.android.wm.shell.shared.IShellTransitions
import com.android.wm.shell.shared.ShellTransitions
@@ -130,7 +131,7 @@
contentBeforeFadeOutDelay = 0L,
contentBeforeFadeOutDuration = 150L,
contentAfterFadeInDelay = 150L,
- contentAfterFadeInDuration = 183L
+ contentAfterFadeInDuration = 183L,
)
/**
@@ -147,7 +148,7 @@
positionInterpolator = Interpolators.EMPHASIZED,
positionXInterpolator = Interpolators.EMPHASIZED_COMPLEMENT,
contentBeforeFadeOutInterpolator = Interpolators.LINEAR_OUT_SLOW_IN,
- contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f)
+ contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f),
)
// TODO(b/288507023): Remove this flag.
@@ -238,7 +239,7 @@
animate: Boolean = true,
packageName: String? = null,
showOverLockscreen: Boolean = false,
- intentStarter: (RemoteAnimationAdapter?) -> Int
+ intentStarter: (RemoteAnimationAdapter?) -> Int,
) {
if (controller == null || !animate) {
Log.i(TAG, "Starting intent with no animation")
@@ -263,7 +264,7 @@
RemoteAnimationAdapter(
runner,
TIMINGS.totalDuration,
- TIMINGS.totalDuration - 150 /* statusBarTransitionDelay */
+ TIMINGS.totalDuration - 150, /* statusBarTransitionDelay */
)
} else {
null
@@ -277,7 +278,7 @@
.registerRemoteAnimationForNextActivityStart(
packageName,
animationAdapter,
- null /* launchCookie */
+ null, /* launchCookie */
)
} catch (e: RemoteException) {
Log.w(TAG, "Unable to register the remote animation", e)
@@ -301,7 +302,7 @@
Log.i(
TAG,
"launchResult=$launchResult willAnimate=$willAnimate " +
- "hideKeyguardWithAnimation=$hideKeyguardWithAnimation"
+ "hideKeyguardWithAnimation=$hideKeyguardWithAnimation",
)
controller.callOnIntentStartedOnMainThread(willAnimate)
@@ -328,7 +329,7 @@
Log.d(
TAG,
"Calling controller.onIntentStarted(willAnimate=$willAnimate) " +
- "[controller=$this]"
+ "[controller=$this]",
)
}
this.onIntentStarted(willAnimate)
@@ -350,7 +351,7 @@
animate: Boolean = true,
packageName: String? = null,
showOverLockscreen: Boolean = false,
- intentStarter: PendingIntentStarter
+ intentStarter: PendingIntentStarter,
) {
startIntentWithAnimation(controller, animate, packageName, showOverLockscreen) {
intentStarter.startPendingIntent(it)
@@ -366,7 +367,7 @@
*/
private fun registerEphemeralReturnAnimation(
launchController: Controller,
- transitionRegister: TransitionRegister?
+ transitionRegister: TransitionRegister?,
) {
if (!returnAnimationFrameworkLibrary()) return
@@ -410,7 +411,7 @@
val transition =
RemoteTransition(
RemoteAnimationRunnerCompat.wrap(returnRunner),
- "${launchController.transitionCookie}_returnTransition"
+ "${launchController.transitionCookie}_returnTransition",
)
transitionRegister?.register(filter, transition)
@@ -508,7 +509,7 @@
cujType: Int? = null,
cookie: TransitionCookie? = null,
component: ComponentName? = null,
- returnCujType: Int? = null
+ returnCujType: Int? = null,
): Controller? {
// Make sure the View we launch from implements LaunchableView to avoid visibility
// issues.
@@ -525,7 +526,7 @@
Log.e(
TAG,
"Skipping animation as view $view is not attached to a ViewGroup",
- Exception()
+ Exception(),
)
return null
}
@@ -535,7 +536,7 @@
cujType,
cookie,
component,
- returnCujType
+ returnCujType,
)
}
}
@@ -646,7 +647,7 @@
val launchRemoteTransition =
RemoteTransition(
RemoteAnimationRunnerCompat.wrap(createRunner(controller)),
- "${cookie}_launchTransition"
+ "${cookie}_launchTransition",
)
transitionRegister.register(launchFilter, launchRemoteTransition)
@@ -668,7 +669,7 @@
val returnRemoteTransition =
RemoteTransition(
RemoteAnimationRunnerCompat.wrap(createRunner(returnController)),
- "${cookie}_returnTransition"
+ "${cookie}_returnTransition",
)
transitionRegister.register(returnFilter, returnRemoteTransition)
@@ -690,7 +691,7 @@
@VisibleForTesting
inner class DelegatingAnimationCompletionListener(
private val delegate: Listener?,
- private val onAnimationComplete: () -> Unit
+ private val onAnimationComplete: () -> Unit,
) : Listener {
var cancelled = false
@@ -723,7 +724,7 @@
/** The animator to use to animate the window transition. */
transitionAnimator: TransitionAnimator,
/** Listener for animation lifecycle events. */
- listener: Listener? = null
+ listener: Listener? = null,
) : IRemoteAnimationRunner.Stub() {
// This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
// etc.) are possible. So we need to make sure we drop any references that might
@@ -748,7 +749,7 @@
apps: Array<out RemoteAnimationTarget>?,
wallpapers: Array<out RemoteAnimationTarget>?,
nonApps: Array<out RemoteAnimationTarget>?,
- finishedCallback: IRemoteAnimationFinishedCallback?
+ finishedCallback: IRemoteAnimationFinishedCallback?,
) {
val delegate = delegate
mainExecutor.execute {
@@ -838,7 +839,7 @@
Log.wtf(
TAG,
"The remote animation was neither cancelled or started within " +
- "$LONG_TRANSITION_TIMEOUT"
+ "$LONG_TRANSITION_TIMEOUT",
)
}
@@ -869,7 +870,7 @@
apps: Array<out RemoteAnimationTarget>?,
wallpapers: Array<out RemoteAnimationTarget>?,
nonApps: Array<out RemoteAnimationTarget>?,
- callback: IRemoteAnimationFinishedCallback?
+ callback: IRemoteAnimationFinishedCallback?,
) {
removeTimeouts()
@@ -894,7 +895,7 @@
if (DEBUG_TRANSITION_ANIMATION) {
Log.d(
TAG,
- "Calling controller.onTransitionAnimationCancelled() [no window opening]"
+ "Calling controller.onTransitionAnimationCancelled() [no window opening]",
)
}
controller.onTransitionAnimationCancelled()
@@ -974,7 +975,7 @@
private fun startAnimation(
window: RemoteAnimationTarget,
navigationBar: RemoteAnimationTarget?,
- iCallback: IRemoteAnimationFinishedCallback?
+ iCallback: IRemoteAnimationFinishedCallback?,
) {
if (TransitionAnimator.DEBUG) {
Log.d(TAG, "Remote animation started")
@@ -983,12 +984,28 @@
val windowBounds = window.screenSpaceBounds
val endState =
if (controller.isLaunching) {
- TransitionAnimator.State(
- top = windowBounds.top,
- bottom = windowBounds.bottom,
- left = windowBounds.left,
- right = windowBounds.right
- )
+ controller.windowAnimatorState?.toTransitionState()
+ ?: TransitionAnimator.State(
+ top = windowBounds.top,
+ bottom = windowBounds.bottom,
+ left = windowBounds.left,
+ right = windowBounds.right,
+ )
+ .apply {
+ // TODO(b/184121838): We should somehow get the top and bottom
+ // radius of the window instead of recomputing isExpandingFullyAbove
+ // here.
+ getWindowRadius(
+ transitionAnimator.isExpandingFullyAbove(
+ controller.transitionContainer,
+ this,
+ )
+ )
+ .let {
+ topCornerRadius = it
+ bottomCornerRadius = it
+ }
+ }
} else {
controller.createAnimatorState()
}
@@ -1000,15 +1017,8 @@
?: window.backgroundColor
}
- // TODO(b/184121838): We should somehow get the top and bottom radius of the window
- // instead of recomputing isExpandingFullyAbove here.
val isExpandingFullyAbove =
transitionAnimator.isExpandingFullyAbove(controller.transitionContainer, endState)
- if (controller.isLaunching) {
- val endRadius = getWindowRadius(isExpandingFullyAbove)
- endState.topCornerRadius = endRadius
- endState.bottomCornerRadius = endRadius
- }
// We animate the opening window and delegate the view expansion to [this.controller].
val delegate = this.controller
@@ -1016,15 +1026,17 @@
object : Controller by delegate {
override fun createAnimatorState(): TransitionAnimator.State {
if (isLaunching) return delegate.createAnimatorState()
- val windowRadius = getWindowRadius(isExpandingFullyAbove)
- return TransitionAnimator.State(
- top = windowBounds.top,
- bottom = windowBounds.bottom,
- left = windowBounds.left,
- right = windowBounds.right,
- topCornerRadius = windowRadius,
- bottomCornerRadius = windowRadius
- )
+ return delegate.windowAnimatorState?.toTransitionState()
+ ?: getWindowRadius(isExpandingFullyAbove).let {
+ TransitionAnimator.State(
+ top = windowBounds.top,
+ bottom = windowBounds.bottom,
+ left = windowBounds.left,
+ right = windowBounds.right,
+ topCornerRadius = it,
+ bottomCornerRadius = it,
+ )
+ }
}
override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -1035,7 +1047,7 @@
TAG,
"Calling controller.onTransitionAnimationStart(" +
"isExpandingFullyAbove=$isExpandingFullyAbove) " +
- "[controller=$delegate]"
+ "[controller=$delegate]",
)
}
delegate.onTransitionAnimationStart(isExpandingFullyAbove)
@@ -1050,7 +1062,7 @@
TAG,
"Calling controller.onTransitionAnimationEnd(" +
"isExpandingFullyAbove=$isExpandingFullyAbove) " +
- "[controller=$delegate]"
+ "[controller=$delegate]",
)
}
delegate.onTransitionAnimationEnd(isExpandingFullyAbove)
@@ -1059,7 +1071,7 @@
override fun onTransitionAnimationProgress(
state: TransitionAnimator.State,
progress: Float,
- linearProgress: Float
+ linearProgress: Float,
) {
applyStateToWindow(window, state, linearProgress)
navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
@@ -1135,7 +1147,7 @@
windowCropF.left.roundToInt(),
windowCropF.top.roundToInt(),
windowCropF.right.roundToInt(),
- windowCropF.bottom.roundToInt()
+ windowCropF.bottom.roundToInt(),
)
val windowAnimationDelay =
@@ -1155,7 +1167,7 @@
TIMINGS,
linearProgress,
windowAnimationDelay,
- windowAnimationDuration
+ windowAnimationDuration,
)
// The alpha of the opening window. If it opens above the expandable, then it should
@@ -1198,7 +1210,7 @@
private fun applyStateToNavigationBar(
navigationBar: RemoteAnimationTarget,
state: TransitionAnimator.State,
- linearProgress: Float
+ linearProgress: Float,
) {
if (transactionApplierView.viewRootImpl == null || !navigationBar.leash.isValid) {
// Don't apply any transaction if the view root we synchronize with was detached or
@@ -1212,7 +1224,7 @@
TIMINGS,
linearProgress,
ANIMATION_DELAY_NAV_FADE_IN,
- ANIMATION_DURATION_NAV_FADE_OUT
+ ANIMATION_DURATION_NAV_FADE_OUT,
)
val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
@@ -1220,7 +1232,7 @@
matrix.reset()
matrix.setTranslate(
0f,
- (state.top - navigationBar.sourceContainerBounds.top).toFloat()
+ (state.top - navigationBar.sourceContainerBounds.top).toFloat(),
)
windowCrop.set(state.left, 0, state.right, state.height)
params
@@ -1234,7 +1246,7 @@
TIMINGS,
linearProgress,
0,
- ANIMATION_DURATION_NAV_FADE_OUT
+ ANIMATION_DURATION_NAV_FADE_OUT,
)
params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
}
@@ -1255,7 +1267,7 @@
if (DEBUG_TRANSITION_ANIMATION) {
Log.d(
TAG,
- "Calling controller.onTransitionAnimationCancelled() [animation timed out]"
+ "Calling controller.onTransitionAnimationCancelled() [animation timed out]",
)
}
controller.onTransitionAnimationCancelled()
@@ -1329,10 +1341,7 @@
}
/** Register [remoteTransition] with WM Shell using the given [filter]. */
- internal fun register(
- filter: TransitionFilter,
- remoteTransition: RemoteTransition,
- ) {
+ internal fun register(filter: TransitionFilter, remoteTransition: RemoteTransition) {
shellTransitions?.registerRemote(filter, remoteTransition)
iShellTransitions?.registerRemote(filter, remoteTransition)
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index 8e824e6..fc4cf1d 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -28,6 +28,7 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
+import android.window.WindowAnimationState
import androidx.annotation.VisibleForTesting
import com.android.app.animation.Interpolators.LINEAR
import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
@@ -56,12 +57,12 @@
timings: Timings,
linearProgress: Float,
delay: Long,
- duration: Long
+ duration: Long,
): Float {
return MathUtils.constrain(
(linearProgress * timings.totalDuration - delay) / duration,
0.0f,
- 1.0f
+ 1.0f,
)
}
@@ -71,6 +72,18 @@
"disabled"
}
}
+
+ internal fun WindowAnimationState.toTransitionState() =
+ State().also {
+ bounds?.let { b ->
+ it.top = b.top.roundToInt()
+ it.left = b.left.roundToInt()
+ it.bottom = b.bottom.roundToInt()
+ it.right = b.right.roundToInt()
+ }
+ it.bottomCornerRadius = (bottomLeftRadius + bottomRightRadius) / 2
+ it.topCornerRadius = (topLeftRadius + topRightRadius) / 2
+ }
}
private val transitionContainerLocation = IntArray(2)
@@ -117,6 +130,15 @@
get() = null
/**
+ * Window state for the animation. If [isLaunching], it would correspond to the end state
+ * otherwise the start state.
+ *
+ * If null, the state is inferred from the window targets
+ */
+ val windowAnimatorState: WindowAnimationState?
+ get() = null
+
+ /**
* Return the [State] of the view that will be animated. We will animate from this state to
* the final window state.
*
@@ -151,7 +173,7 @@
var left: Int = 0,
var right: Int = 0,
var topCornerRadius: Float = 0f,
- var bottomCornerRadius: Float = 0f
+ var bottomCornerRadius: Float = 0f,
) {
private val startTop = top
@@ -197,7 +219,7 @@
val contentAfterFadeInDelay: Long,
/** The duration of the expanded content fade in. */
- val contentAfterFadeInDuration: Long
+ val contentAfterFadeInDuration: Long,
)
/** The interpolators used by this animator. */
@@ -215,7 +237,7 @@
val contentBeforeFadeOutInterpolator: Interpolator,
/** The interpolator used when fading in the expanded content. */
- val contentAfterFadeInInterpolator: Interpolator
+ val contentAfterFadeInInterpolator: Interpolator,
)
/**
@@ -254,7 +276,7 @@
endState,
windowBackgroundLayer,
fadeWindowBackgroundLayer,
- drawHole
+ drawHole,
)
animator.start()
@@ -271,7 +293,7 @@
endState: State,
windowBackgroundLayer: GradientDrawable,
fadeWindowBackgroundLayer: Boolean = true,
- drawHole: Boolean = false
+ drawHole: Boolean = false,
): ValueAnimator {
val state = controller.createAnimatorState()
@@ -399,14 +421,14 @@
timings,
linearProgress,
timings.contentBeforeFadeOutDelay,
- timings.contentBeforeFadeOutDuration
+ timings.contentBeforeFadeOutDuration,
) < 1
} else {
getProgress(
timings,
linearProgress,
timings.contentAfterFadeInDelay,
- timings.contentAfterFadeInDuration
+ timings.contentAfterFadeInDuration,
) > 0
}
@@ -427,7 +449,7 @@
ViewRootSync.synchronizeNextDraw(
transitionContainer,
openingWindowSyncView,
- then = {}
+ then = {},
)
} else if (
!controller.isLaunching &&
@@ -446,7 +468,7 @@
ViewRootSync.synchronizeNextDraw(
openingWindowSyncView,
transitionContainer,
- then = {}
+ then = {},
)
}
@@ -464,7 +486,7 @@
container,
fadeWindowBackgroundLayer,
drawHole,
- controller.isLaunching
+ controller.isLaunching,
)
controller.onTransitionAnimationProgress(state, progress, linearProgress)
}
@@ -488,7 +510,7 @@
transitionContainer: View,
fadeWindowBackgroundLayer: Boolean,
drawHole: Boolean,
- isLaunching: Boolean
+ isLaunching: Boolean,
) {
// Update position.
transitionContainer.getLocationOnScreen(transitionContainerLocation)
@@ -496,7 +518,7 @@
state.left - transitionContainerLocation[0],
state.top - transitionContainerLocation[1],
state.right - transitionContainerLocation[0],
- state.bottom - transitionContainerLocation[1]
+ state.bottom - transitionContainerLocation[1],
)
// Update radius.
@@ -517,7 +539,7 @@
timings,
linearProgress,
timings.contentBeforeFadeOutDelay,
- timings.contentBeforeFadeOutDuration
+ timings.contentBeforeFadeOutDuration,
)
if (isLaunching) {
@@ -531,7 +553,7 @@
timings,
linearProgress,
timings.contentAfterFadeInDelay,
- timings.contentAfterFadeInDuration
+ timings.contentAfterFadeInDuration,
)
val alpha =
1 -
@@ -561,7 +583,7 @@
timings,
linearProgress,
timings.contentAfterFadeInDelay,
- timings.contentAfterFadeInDuration
+ timings.contentAfterFadeInDuration,
)
val alpha =
1 -
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt
deleted file mode 100644
index c58df35..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene
-
-import com.android.systemui.notifications.ui.composable.NotificationsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface NotificationsShadeSceneModule {
-
- @Binds @IntoSet fun notificationsShade(scene: NotificationsShadeScene): Scene
-}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
deleted file mode 100644
index 5bb6ae4..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene
-
-import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface QuickSettingsShadeSceneModule {
-
- @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index 34eafde..d326f00 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -830,7 +830,7 @@
Image(
bitmap = it.asImageBitmap(),
contentDescription = null,
- modifier = Modifier.size(SelectedUserImageSize),
+ modifier = Modifier.size(SelectedUserImageSize).sysuiResTag("user_icon"),
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 480e4e4..489e24e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.ui.composable
import android.view.HapticFeedbackConstants
+import android.view.MotionEvent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
@@ -49,6 +50,7 @@
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -61,6 +63,7 @@
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.res.R
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
@@ -101,7 +104,7 @@
columns = columns,
verticalSpacing = verticalSpacing,
horizontalSpacing = calculateHorizontalSpacingBetweenColumns(gridWidth = 300.dp),
- modifier = modifier.focusRequester(focusRequester)
+ modifier = modifier.focusRequester(focusRequester).sysuiResTag("pin_pad_grid")
) {
repeat(9) { index ->
DigitButton(
@@ -110,6 +113,7 @@
onClicked = viewModel::onPinButtonClicked,
scaling = buttonScaleAnimatables[index]::value,
isAnimationEnabled = isDigitButtonAnimationEnabled,
+ onPointerDown = viewModel::onDigitButtonDown,
)
}
@@ -125,6 +129,7 @@
onLongPressed = viewModel::onBackspaceButtonLongPressed,
appearance = backspaceButtonAppearance,
scaling = buttonScaleAnimatables[9]::value,
+ elementId = "delete_button"
)
DigitButton(
@@ -133,6 +138,7 @@
onClicked = viewModel::onPinButtonClicked,
scaling = buttonScaleAnimatables[10]::value,
isAnimationEnabled = isDigitButtonAnimationEnabled,
+ onPointerDown = viewModel::onDigitButtonDown
)
ActionButton(
@@ -146,6 +152,7 @@
onClicked = viewModel::onAuthenticateButtonClicked,
appearance = confirmButtonAppearance,
scaling = buttonScaleAnimatables[11]::value,
+ elementId = "key_enter"
)
}
}
@@ -155,6 +162,7 @@
digit: Int,
isInputEnabled: Boolean,
onClicked: (Int) -> Unit,
+ onPointerDown: () -> Unit,
scaling: () -> Float,
isAnimationEnabled: Boolean,
) {
@@ -164,6 +172,7 @@
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant,
isAnimationEnabled = isAnimationEnabled,
+ onPointerDown = onPointerDown,
modifier =
Modifier.graphicsLayer {
val scale = if (isAnimationEnabled) scaling() else 1f
@@ -186,6 +195,7 @@
icon: Icon,
isInputEnabled: Boolean,
onClicked: () -> Unit,
+ elementId: String,
onLongPressed: (() -> Unit)? = null,
appearance: ActionButtonAppearance,
scaling: () -> Float,
@@ -211,6 +221,7 @@
backgroundColor = backgroundColor,
foregroundColor = foregroundColor,
isAnimationEnabled = true,
+ elementId = elementId,
modifier =
Modifier.graphicsLayer {
alpha = hiddenAlpha
@@ -234,7 +245,9 @@
foregroundColor: Color,
isAnimationEnabled: Boolean,
modifier: Modifier = Modifier,
+ elementId: String? = null,
onLongPressed: (() -> Unit)? = null,
+ onPointerDown: (() -> Unit)? = null,
content: @Composable (contentColor: () -> Color) -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
@@ -303,12 +316,19 @@
.clip(CircleShape)
.thenIf(isEnabled) {
Modifier.combinedClickable(
- interactionSource = interactionSource,
- indication = indication,
- onClick = onClicked,
- onLongClick = onLongPressed
- )
- },
+ interactionSource = interactionSource,
+ indication = indication,
+ onClick = onClicked,
+ onLongClick = onLongPressed
+ )
+ .pointerInteropFilter { motionEvent ->
+ if (motionEvent.action == MotionEvent.ACTION_DOWN) {
+ onPointerDown?.let { it() }
+ }
+ false
+ }
+ }
+ .thenIf(elementId != null) { Modifier.sysuiResTag(elementId!!) },
) {
content(contentColor::value)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index a4dc8fc..557257d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -72,7 +72,7 @@
override fun matches(key: ElementKey, content: ContentKey) = true
}
-private object TransitionDuration {
+object TransitionDuration {
const val BETWEEN_HUB_AND_EDIT_MODE_MS = 1000
const val EDIT_MODE_TO_HUB_CONTENT_MS = 167
const val EDIT_MODE_TO_HUB_GRID_DELAY_MS = 167
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index efe0f2e..f4d1242 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -108,6 +108,8 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
@@ -179,6 +181,7 @@
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@@ -1155,6 +1158,15 @@
val selectedIndex =
selectedKey?.let { key -> contentListState.list.indexOfFirst { it.key == key } }
+ val interactionSource = remember { MutableInteractionSource() }
+ val focusRequester = remember { FocusRequester() }
+ if (viewModel.isEditMode && selected) {
+ LaunchedEffect(Unit) {
+ delay(TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS.toLong())
+ focusRequester.requestFocus()
+ }
+ }
+
val isSelected = selectedKey == model.key
val selectableModifier =
@@ -1162,7 +1174,7 @@
Modifier.selectable(
selected = isSelected,
onClick = { viewModel.setSelectedKey(model.key) },
- interactionSource = remember { MutableInteractionSource() },
+ interactionSource = interactionSource,
indication = null,
)
} else {
@@ -1172,6 +1184,8 @@
Box(
modifier =
modifier
+ .focusRequester(focusRequester)
+ .focusable(interactionSource = interactionSource)
.then(selectableModifier)
.thenIf(!viewModel.isEditMode && !model.inQuietMode) {
Modifier.pointerInput(Unit) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
deleted file mode 100644
index 1f4cd04..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.notifications.ui.composable
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeUserActionsViewModel
-import com.android.systemui.scene.session.ui.composable.SaveableSession
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.shade.shared.model.ShadeMode
-import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
-import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
-import com.android.systemui.statusbar.phone.ui.StatusBarIconController
-import com.android.systemui.statusbar.phone.ui.TintedIconManager
-import dagger.Lazy
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-@SysUISingleton
-class NotificationsShadeScene
-@Inject
-constructor(
- private val actionsViewModelFactory: NotificationsShadeUserActionsViewModel.Factory,
- private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
- private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
- private val tintedIconManagerFactory: TintedIconManager.Factory,
- private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
- private val statusBarIconController: StatusBarIconController,
- private val shadeSession: SaveableSession,
- private val stackScrollView: Lazy<NotificationScrollView>,
-) : ExclusiveActivatable(), Scene {
-
- override val key = Scenes.NotificationsShade
-
- private val actionsViewModel: NotificationsShadeUserActionsViewModel by lazy {
- actionsViewModelFactory.create()
- }
-
- override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
-
- override suspend fun onActivated(): Nothing {
- actionsViewModel.activate()
- }
-
- @Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- val notificationsPlaceholderViewModel =
- rememberViewModel("NotificationsShadeScene") {
- notificationsPlaceholderViewModelFactory.create()
- }
-
- OverlayShade(
- modifier = modifier,
- onScrimClicked = {},
- ) {
- Column {
- ExpandedShadeHeader(
- viewModelFactory = shadeHeaderViewModelFactory,
- createTintedIconManager = tintedIconManagerFactory::create,
- createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
- statusBarIconController = statusBarIconController,
- modifier = Modifier.padding(horizontal = 16.dp),
- )
-
- NotificationScrollingStack(
- shadeSession = shadeSession,
- stackScrollView = stackScrollView.get(),
- viewModel = notificationsPlaceholderViewModel,
- maxScrimTop = { 0f },
- shouldPunchHoleBehindScrim = false,
- shouldFillMaxSize = false,
- shouldReserveSpaceForNavBar = false,
- shadeMode = ShadeMode.Dual,
- modifier = Modifier.fillMaxWidth(),
- )
-
- // Communicates the bottom position of the drawable area within the shade to NSSL.
- NotificationStackCutoffGuideline(
- stackScrollView = stackScrollView.get(),
- viewModel = notificationsPlaceholderViewModel,
- )
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 671b012..a6d5c1c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -48,17 +48,13 @@
import com.android.systemui.scene.shared.model.Scenes
object QuickSettings {
- private val SCENES =
- setOf(
- Scenes.QuickSettings,
- Scenes.Shade,
- )
+ private val SCENES = setOf(Scenes.QuickSettings, Scenes.Shade)
object Elements {
val Content =
MovableElementKey(
"QuickSettingsContent",
- contentPicker = MovableElementContentPicker(SCENES)
+ contentPicker = MovableElementContentPicker(SCENES),
)
val QuickQuickSettings = ElementKey("QuickQuickSettings")
val SplitShadeQuickSettings = ElementKey("SplitShadeQuickSettings")
@@ -87,7 +83,7 @@
private fun SceneScope.stateForQuickSettingsContent(
isSplitShade: Boolean,
- squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default }
+ squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default },
): QSSceneAdapter.State {
return when (val transitionState = layoutState.transitionState) {
is TransitionState.Idle -> {
@@ -122,7 +118,7 @@
}
}
is TransitionState.Transition.OverlayTransition ->
- TODO("b/359173565: Handle overlay transitions")
+ error("Bad transition for QuickSettings scene: overlays not supported")
}
}
@@ -172,7 +168,7 @@
val height = heightProvider().coerceAtLeast(0)
layout(placeable.width, height) { placeable.placeRelative(0, 0) }
- }
+ },
) {
content { QuickSettingsContent(qsSceneAdapter = qsSceneAdapter, contentState) }
}
@@ -225,7 +221,7 @@
it.addView(view)
}
},
- onRelease = { it.removeAllViews() }
+ onRelease = { it.removeAllViews() },
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index d34295e..fa92bef34 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -64,6 +64,7 @@
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -146,9 +147,7 @@
}
@Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
+ override fun SceneScope.Content(modifier: Modifier) {
QuickSettingsScene(
notificationStackScrollView = notificationStackScrollView.get(),
viewModelFactory = contentViewModelFactory,
@@ -199,13 +198,17 @@
onDispose { notificationsPlaceholderViewModel.setAlphaForBrightnessMirror(1f) }
}
+ val shadeHorizontalPadding =
+ dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
+
BrightnessMirror(
viewModel = brightnessMirrorViewModel,
qsSceneAdapter = viewModel.qsSceneAdapter,
modifier =
Modifier.thenIf(cutoutLocation != CutoutLocation.CENTER) {
- Modifier.displayCutoutPadding()
- }
+ Modifier.displayCutoutPadding()
+ }
+ .padding(horizontal = shadeHorizontalPadding),
)
val shouldPunchHoleBehindScrim =
@@ -224,9 +227,7 @@
// scene (and not the one under it) during a scene transition.
Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
}
- .thenIf(cutoutLocation != CutoutLocation.CENTER) {
- Modifier.displayCutoutPadding()
- },
+ .thenIf(cutoutLocation != CutoutLocation.CENTER) { Modifier.displayCutoutPadding() }
) {
val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
val isCustomizerShowing by
@@ -235,11 +236,7 @@
viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle()
val screenHeight = LocalRawScreenHeight.current
- BackHandler(
- enabled = isCustomizing,
- ) {
- viewModel.qsSceneAdapter.requestCloseCustomizer()
- }
+ BackHandler(enabled = isCustomizing) { viewModel.qsSceneAdapter.requestCloseCustomizer() }
val collapsedHeaderHeight =
with(LocalDensity.current) { ShadeHeader.Dimensions.CollapsedHeight.roundToPx() }
@@ -276,13 +273,13 @@
animateDpAsState(
targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
animationSpec = tween(customizingAnimationDuration),
- label = "animateQSSceneBottomPaddingAsState"
+ label = "animateQSSceneBottomPaddingAsState",
)
val topPadding by
animateDpAsState(
targetValue = if (isCustomizing) ShadeHeader.Dimensions.CollapsedHeight else 0.dp,
animationSpec = tween(customizingAnimationDuration),
- label = "animateQSSceneTopPaddingAsState"
+ label = "animateQSSceneTopPaddingAsState",
)
LaunchedEffect(navBarBottomHeight, density) {
@@ -313,18 +310,15 @@
Modifier.fillMaxSize()
.padding(
top = topPadding.coerceAtLeast(0.dp),
- bottom = bottomPadding.coerceAtLeast(0.dp)
- )
+ bottom = bottomPadding.coerceAtLeast(0.dp),
+ ),
) {
Box(modifier = Modifier.fillMaxSize().weight(1f)) {
val shadeHeaderAndQuickSettingsModifier =
if (isCustomizerShowing) {
Modifier.fillMaxHeight().align(Alignment.TopCenter)
} else {
- Modifier.verticalScroll(
- scrollState,
- enabled = isScrollable,
- )
+ Modifier.verticalScroll(scrollState, enabled = isScrollable)
.clipScrollableContainer(Orientation.Horizontal)
.fillMaxWidth()
.wrapContentHeight(unbounded = true)
@@ -333,7 +327,7 @@
Column(
modifier =
- shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view"),
+ shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view")
) {
when (LocalWindowSizeClass.current.widthSizeClass) {
WindowWidthSizeClass.Compact ->
@@ -345,7 +339,7 @@
expandFrom = Alignment.Top,
) +
slideInVertically(
- animationSpec = tween(customizingAnimationDuration),
+ animationSpec = tween(customizingAnimationDuration)
) +
fadeIn(tween(customizingAnimationDuration)),
exit =
@@ -354,7 +348,7 @@
shrinkTowards = Alignment.Top,
) +
slideOutVertically(
- animationSpec = tween(customizingAnimationDuration),
+ animationSpec = tween(customizingAnimationDuration)
) +
fadeOut(tween(customizingAnimationDuration)),
) {
@@ -382,7 +376,7 @@
viewModel.qsSceneAdapter,
{ viewModel.qsSceneAdapter.qsHeight },
isSplitShade = false,
- modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS)
+ modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS),
)
MediaCarousel(
@@ -400,13 +394,12 @@
{ mediaOffset.roundToPx() },
)
}
- if (mediaInRow) {
- Layout(
- content = content,
- measurePolicy = landscapeQsMediaMeasurePolicy,
- )
- } else {
- content()
+ Box(modifier = Modifier.padding(horizontal = shadeHorizontalPadding)) {
+ if (mediaInRow) {
+ Layout(content = content, measurePolicy = landscapeQsMediaMeasurePolicy)
+ } else {
+ content()
+ }
}
}
}
@@ -417,13 +410,18 @@
customizingAnimationDuration = customizingAnimationDuration,
lifecycleOwner = lifecycleOwner,
modifier =
- Modifier.align(Alignment.CenterHorizontally).sysuiResTag("qs_footer_actions"),
+ Modifier.align(Alignment.CenterHorizontally)
+ .sysuiResTag("qs_footer_actions")
+ .padding(horizontal = shadeHorizontalPadding),
)
}
HeadsUpNotificationSpace(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),
+ modifier =
+ Modifier.align(Alignment.BottomCenter)
+ .navigationBarsPadding()
+ .padding(horizontal = shadeHorizontalPadding),
isPeekFromBottom = true,
)
NotificationScrollingStack(
@@ -435,15 +433,18 @@
shouldIncludeHeadsUpSpace = false,
shadeMode = ShadeMode.Single,
modifier =
- Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) },
+ Modifier.fillMaxWidth()
+ .offset { IntOffset(x = 0, y = screenHeight.roundToInt()) }
+ .padding(horizontal = shadeHorizontalPadding),
)
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
modifier =
- Modifier.align(Alignment.BottomCenter).navigationBarsPadding().offset {
- IntOffset(x = 0, y = screenHeight.roundToInt())
- }
+ Modifier.align(Alignment.BottomCenter)
+ .navigationBarsPadding()
+ .offset { IntOffset(x = 0, y = screenHeight.roundToInt()) }
+ .padding(horizontal = shadeHorizontalPadding),
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
deleted file mode 100644
index e27c7e2..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.qs.ui.composable
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneContentViewModel
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeUserActionsViewModel
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
-import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.phone.ui.StatusBarIconController
-import com.android.systemui.statusbar.phone.ui.TintedIconManager
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-@SysUISingleton
-class QuickSettingsShadeScene
-@Inject
-constructor(
- private val actionsViewModelFactory: QuickSettingsShadeUserActionsViewModel.Factory,
- private val contentViewModelFactory: QuickSettingsShadeSceneContentViewModel.Factory,
- private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
- private val tintedIconManagerFactory: TintedIconManager.Factory,
- private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
- private val statusBarIconController: StatusBarIconController,
-) : ExclusiveActivatable(), Scene {
-
- override val key = Scenes.QuickSettingsShade
-
- private val actionsViewModel: QuickSettingsShadeUserActionsViewModel by lazy {
- actionsViewModelFactory.create()
- }
-
- override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
-
- override suspend fun onActivated(): Nothing {
- actionsViewModel.activate()
- }
-
- @Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- val viewModel =
- rememberViewModel("QuickSettingsShadeScene") { contentViewModelFactory.create() }
-
- OverlayShade(
- modifier = modifier,
- onScrimClicked = {},
- ) {
- Column {
- ExpandedShadeHeader(
- viewModelFactory = shadeHeaderViewModelFactory,
- createTintedIconManager = tintedIconManagerFactory::create,
- createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
- statusBarIconController = statusBarIconController,
- modifier = Modifier.padding(QuickSettingsShade.Dimensions.Padding),
- )
-
- ShadeBody(
- viewModel = viewModel.quickSettingsContainerViewModel,
- )
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index f660808..f64d0ed 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -6,6 +6,7 @@
import com.android.compose.animation.scene.transitions
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
@@ -20,7 +21,11 @@
import com.android.systemui.scene.ui.composable.transitions.lockscreenToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToShadeTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToSplitShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.notificationsShadeToQuickSettingsShadeTransition
import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition
+import com.android.systemui.scene.ui.composable.transitions.toNotificationsShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.toQuickSettingsShadeTransition
+import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.Shade
/**
@@ -74,6 +79,14 @@
from(Scenes.Lockscreen, to = Scenes.Gone) { lockscreenToGoneTransition() }
from(Scenes.Shade, to = Scenes.QuickSettings) { shadeToQuickSettingsTransition() }
+ // Overlay transitions
+
+ to(Overlays.NotificationsShade) { toNotificationsShadeTransition() }
+ to(Overlays.QuickSettingsShade) { toQuickSettingsShadeTransition() }
+ from(Overlays.NotificationsShade, Overlays.QuickSettingsShade) {
+ notificationsShadeToQuickSettingsShadeTransition()
+ }
+
// Scene overscroll
overscrollDisabled(Scenes.Gone, Orientation.Vertical)
@@ -91,4 +104,10 @@
y = Shade.Dimensions.ScrimOverscrollLimit,
)
}
+ overscroll(Overlays.NotificationsShade, Orientation.Vertical) {
+ translate(OverlayShade.Elements.Panel, y = OverlayShade.Dimensions.OverscrollLimit)
+ }
+ overscroll(Overlays.QuickSettingsShade, Orientation.Vertical) {
+ translate(OverlayShade.Elements.Panel, y = OverlayShade.Dimensions.OverscrollLimit)
+ }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt
deleted file mode 100644
index 8a03e29..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.Edge
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToQuickSettingsShadeTransition(
- edge: Edge = Edge.Top,
- durationScale: Double = 1.0,
-) {
- toQuickSettingsShadeTransition(edge, durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
deleted file mode 100644
index 02664c1..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.lockscreenToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale = durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt
deleted file mode 100644
index 19aa3a7..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.Edge
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.lockscreenToQuickSettingsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toQuickSettingsShadeTransition(Edge.Top, durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt
new file mode 100644
index 0000000..24f285e
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.composable.transitions
+
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.shade.ui.composable.Shade
+import kotlin.time.Duration.Companion.milliseconds
+
+fun TransitionBuilder.notificationsShadeToQuickSettingsShadeTransition(
+ durationScale: Double = 1.0
+) {
+ spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
+ swipeSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
+ )
+}
+
+private val DefaultDuration = 300.milliseconds
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
index 9d13647..55fa6ad 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
@@ -26,10 +26,7 @@
import com.android.systemui.shade.ui.composable.Shade
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.toQuickSettingsShadeTransition(
- edge: Edge = Edge.Top,
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.toQuickSettingsShadeTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
swipeSpec =
spring(
@@ -38,7 +35,7 @@
)
distance = UserActionDistance { fromSceneSize, _ -> fromSceneSize.height.toFloat() * 2 / 3f }
- translate(OverlayShade.Elements.Panel, edge)
+ translate(OverlayShade.Elements.Panel, Edge.Top)
fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 8922224..b85523b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -61,23 +61,17 @@
Box(modifier) {
Scrim(onClicked = onScrimClicked)
- Box(
- modifier = Modifier.fillMaxSize().panelPadding(),
- contentAlignment = Alignment.TopEnd,
- ) {
+ Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) {
Panel(
modifier = Modifier.element(OverlayShade.Elements.Panel).panelSize(),
- content = content
+ content = content,
)
}
}
}
@Composable
-private fun SceneScope.Scrim(
- onClicked: () -> Unit,
- modifier: Modifier = Modifier,
-) {
+private fun SceneScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) {
Spacer(
modifier =
modifier
@@ -89,10 +83,7 @@
}
@Composable
-private fun SceneScope.Panel(
- modifier: Modifier = Modifier,
- content: @Composable () -> Unit,
-) {
+private fun SceneScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) {
Spacer(
modifier =
@@ -101,7 +92,7 @@
.background(
color = OverlayShade.Colors.PanelBackground,
shape = OverlayShade.Shapes.RoundedCornerPanel,
- ),
+ )
)
// This content is intentionally rendered as a separate element from the background in order
@@ -137,7 +128,7 @@
systemBars.asPaddingValues(),
displayCutout.asPaddingValues(),
waterfall.asPaddingValues(),
- contentPadding
+ contentPadding,
)
return if (widthSizeClass == WindowWidthSizeClass.Compact) {
@@ -156,14 +147,19 @@
start = paddingValues.maxOfOrNull { it.calculateStartPadding(layoutDirection) } ?: 0.dp,
top = paddingValues.maxOfOrNull { it.calculateTopPadding() } ?: 0.dp,
end = paddingValues.maxOfOrNull { it.calculateEndPadding(layoutDirection) } ?: 0.dp,
- bottom = paddingValues.maxOfOrNull { it.calculateBottomPadding() } ?: 0.dp
+ bottom = paddingValues.maxOfOrNull { it.calculateBottomPadding() } ?: 0.dp,
)
}
object OverlayShade {
object Elements {
val Scrim = ElementKey("OverlayShadeScrim", contentPicker = LowestZIndexContentPicker)
- val Panel = ElementKey("OverlayShadePanel", contentPicker = LowestZIndexContentPicker)
+ val Panel =
+ ElementKey(
+ "OverlayShadePanel",
+ contentPicker = LowestZIndexContentPicker,
+ placeAllCopies = true,
+ )
val PanelBackground =
ElementKey("OverlayShadePanelBackground", contentPicker = LowestZIndexContentPicker)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index df22264..8a59e20 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.ui.composable
+import android.view.HapticFeedbackConstants
import android.view.ViewGroup
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
@@ -60,6 +61,7 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
@@ -178,9 +180,7 @@
override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
@Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) =
+ override fun SceneScope.Content(modifier: Modifier) =
ShadeScene(
notificationStackScrollView.get(),
viewModel =
@@ -224,6 +224,13 @@
modifier: Modifier = Modifier,
shadeSession: SaveableSession,
) {
+ val view = LocalView.current
+ LaunchedEffect(Unit) {
+ if (layoutState.currentTransition?.fromContent == Scenes.Gone) {
+ view.performHapticFeedback(HapticFeedbackConstants.GESTURE_START)
+ }
+ }
+
val shadeMode by viewModel.shadeMode.collectAsStateWithLifecycle()
when (shadeMode) {
is ShadeMode.Single ->
@@ -282,7 +289,7 @@
animateSceneFloatAsState(
value = 1f,
key = QuickSettings.SharedValues.TilesSquishiness,
- canOverflow = false
+ canOverflow = false,
)
val isEmptySpaceClickable by viewModel.isEmptySpaceClickable.collectAsStateWithLifecycle()
val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
@@ -320,7 +327,7 @@
} else {
cutoutInsets
}
- }
+ },
)
}
@@ -337,7 +344,7 @@
modifier =
Modifier.fillMaxSize()
.element(Shade.Elements.BackgroundScrim)
- .background(colorResource(R.color.shade_scrim_background_dark)),
+ .background(colorResource(R.color.shade_scrim_background_dark))
)
Layout(
modifier =
@@ -398,13 +405,13 @@
.pointerInteropFilter { true }
.verticalNestedScrollToScene(
topBehavior = NestedScrollBehavior.EdgeAlways,
- isExternalOverscrollGesture = { false }
+ isExternalOverscrollGesture = { false },
)
) {
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.TopCenter)
+ modifier = Modifier.align(Alignment.TopCenter),
)
}
}
@@ -440,24 +447,16 @@
canOverflow = false,
)
val unfoldTranslationXForStartSide by
- viewModel
- .unfoldTranslationX(
- isOnStartSide = true,
- )
- .collectAsStateWithLifecycle(0f)
+ viewModel.unfoldTranslationX(isOnStartSide = true).collectAsStateWithLifecycle(0f)
val unfoldTranslationXForEndSide by
- viewModel
- .unfoldTranslationX(
- isOnStartSide = false,
- )
- .collectAsStateWithLifecycle(0f)
+ viewModel.unfoldTranslationX(isOnStartSide = false).collectAsStateWithLifecycle(0f)
val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
val bottomPadding by
animateDpAsState(
targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
animationSpec = tween(customizingAnimationDuration),
- label = "animateQSSceneBottomPaddingAsState"
+ label = "animateQSSceneBottomPaddingAsState",
)
val density = LocalDensity.current
LaunchedEffect(navBarBottomHeight, density) {
@@ -516,9 +515,7 @@
)
)
- Column(
- modifier = Modifier.fillMaxSize(),
- ) {
+ Column(modifier = Modifier.fillMaxSize()) {
CollapsedShadeHeader(
viewModelFactory = viewModel.shadeHeaderViewModelFactory,
createTintedIconManager = createTintedIconManager,
@@ -526,9 +523,7 @@
statusBarIconController = statusBarIconController,
modifier =
Modifier.then(brightnessMirrorShowingModifier)
- .padding(
- horizontal = { unfoldTranslationXForStartSide.roundToInt() },
- )
+ .padding(horizontal = { unfoldTranslationXForStartSide.roundToInt() }),
)
Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
@@ -536,14 +531,14 @@
modifier =
Modifier.element(Shade.Elements.SplitShadeStartColumn)
.weight(1f)
- .graphicsLayer { translationX = unfoldTranslationXForStartSide },
+ .graphicsLayer { translationX = unfoldTranslationXForStartSide }
) {
BrightnessMirror(
viewModel = brightnessMirrorViewModel,
qsSceneAdapter = viewModel.qsSceneAdapter,
// Need to use the offset measured from the container as the header
// has to be accounted for
- measureFromContainer = true
+ measureFromContainer = true,
)
Column(
verticalArrangement = Arrangement.Top,
@@ -557,7 +552,7 @@
.thenIf(!isCustomizerShowing) {
Modifier.verticalScroll(
quickSettingsScrollState,
- enabled = isScrollable
+ enabled = isScrollable,
)
.clipScrollableContainer(Orientation.Horizontal)
}
@@ -619,16 +614,16 @@
.padding(
end =
dimensionResource(R.dimen.notification_panel_margin_horizontal),
- bottom = navBarBottomHeight
+ bottom = navBarBottomHeight,
)
- .then(brightnessMirrorShowingModifier)
+ .then(brightnessMirrorShowingModifier),
)
}
}
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding()
+ modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),
)
}
}
@@ -652,6 +647,6 @@
null
} else {
{ mediaOffsetProvider.offset }
- }
+ },
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 5a084db..ebe1df4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -813,6 +813,10 @@
element: Element,
elementState: TransitionState,
): Boolean {
+ if (element.key.placeAllCopies) {
+ return true
+ }
+
val transition =
when (elementState) {
is TransitionState.Idle -> {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
index f9a9eeb..2e7488b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
@@ -79,6 +79,16 @@
* or compose MovableElements.
*/
open val contentPicker: ElementContentPicker = DefaultElementContentPicker,
+
+ /**
+ * Whether we should place all copies of this element when it is shared.
+ *
+ * This should usually be false, but it can be useful when sharing a container that has a
+ * different content in different scenes/overlays. That way the container will have the same
+ * size and position in all scenes/overlays but all different contents will be placed and
+ * visible on screen.
+ */
+ val placeAllCopies: Boolean = false,
) : Key(debugName, identity), ElementMatcher {
@VisibleForTesting
// TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index 1f26b71..6a5b7e1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -37,7 +37,7 @@
modifier: Modifier,
content: @Composable ElementScope<ElementContentScope>.() -> Unit,
) {
- Box(modifier.element(layoutImpl, sceneOrOverlay, key)) {
+ Box(modifier.element(layoutImpl, sceneOrOverlay, key), propagateMinConstraints = true) {
val contentScope = sceneOrOverlay.scope
val boxScope = this
val elementScope =
@@ -64,7 +64,7 @@
"MovableElementKey($elementName).contentPicker.contents does not contain $contentName"
}
- Box(modifier.element(layoutImpl, sceneOrOverlay, key)) {
+ Box(modifier.element(layoutImpl, sceneOrOverlay, key), propagateMinConstraints = true) {
val contentScope = sceneOrOverlay.scope
val boxScope = this
val elementScope =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 30eb302..077927d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -50,7 +50,8 @@
fun currentOverlays(): Flow<Set<OverlayKey>> {
return when (this) {
is Idle -> flowOf(currentOverlays)
- is Transition -> currentOverlays
+ is Transition.ChangeScene -> flowOf(currentOverlays)
+ is Transition.OverlayTransition -> currentOverlays
}
}
@@ -64,7 +65,6 @@
sealed class Transition(
val fromContent: ContentKey,
val toContent: ContentKey,
- val currentOverlays: Flow<Set<OverlayKey>>,
val progress: Flow<Float>,
/**
@@ -105,7 +105,7 @@
val fromScene: SceneKey,
val toScene: SceneKey,
val currentScene: Flow<SceneKey>,
- currentOverlays: Set<OverlayKey>,
+ val currentOverlays: Set<OverlayKey>,
progress: Flow<Float>,
isInitiatedByUserInput: Boolean,
isUserInputOngoing: Flow<Boolean>,
@@ -115,7 +115,31 @@
Transition(
fromScene,
toScene,
- flowOf(currentOverlays),
+ progress,
+ isInitiatedByUserInput,
+ isUserInputOngoing,
+ previewProgress,
+ isInPreviewStage,
+ )
+
+ /**
+ * A transition that is animating one or more overlays and for which [currentOverlays] will
+ * change over the course of the transition.
+ */
+ sealed class OverlayTransition(
+ fromContent: ContentKey,
+ toContent: ContentKey,
+ val currentScene: SceneKey,
+ val currentOverlays: Flow<Set<OverlayKey>>,
+ progress: Flow<Float>,
+ isInitiatedByUserInput: Boolean,
+ isUserInputOngoing: Flow<Boolean>,
+ previewProgress: Flow<Float>,
+ isInPreviewStage: Flow<Boolean>,
+ ) :
+ Transition(
+ fromContent,
+ toContent,
progress,
isInitiatedByUserInput,
isUserInputOngoing,
@@ -128,7 +152,7 @@
val overlay: OverlayKey,
fromContent: ContentKey,
toContent: ContentKey,
- val currentScene: SceneKey,
+ currentScene: SceneKey,
currentOverlays: Flow<Set<OverlayKey>>,
progress: Flow<Float>,
isInitiatedByUserInput: Boolean,
@@ -136,9 +160,10 @@
previewProgress: Flow<Float>,
isInPreviewStage: Flow<Boolean>,
) :
- Transition(
+ OverlayTransition(
fromContent,
toContent,
+ currentScene,
currentOverlays,
progress,
isInitiatedByUserInput,
@@ -151,7 +176,7 @@
class ReplaceOverlay(
val fromOverlay: OverlayKey,
val toOverlay: OverlayKey,
- val currentScene: SceneKey,
+ currentScene: SceneKey,
currentOverlays: Flow<Set<OverlayKey>>,
progress: Flow<Float>,
isInitiatedByUserInput: Boolean,
@@ -159,9 +184,10 @@
previewProgress: Flow<Float>,
isInPreviewStage: Flow<Boolean>,
) :
- Transition(
+ OverlayTransition(
fromOverlay,
toOverlay,
+ currentScene,
currentOverlays,
progress,
isInitiatedByUserInput,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index f20548b..cec8883 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -100,6 +100,10 @@
* By default overlays are centered in their layout but they can be aligned differently using
* [alignment].
*
+ * If [isModal] is true (the default), then a protective layer will be added behind the overlay
+ * to prevent swipes from reaching other scenes or overlays behind this one. Clicking this
+ * protective layer will close the overlay.
+ *
* Important: overlays must be defined after all scenes. Overlay order along the z-axis follows
* call order. Calling overlay(A) followed by overlay(B) will mean that overlay B renders
* after/above overlay A.
@@ -109,6 +113,7 @@
userActions: Map<UserAction, UserActionResult> =
mapOf(Back to UserActionResult.HideOverlay(key)),
alignment: Alignment = Alignment.Center,
+ isModal: Boolean = true,
content: @Composable ContentScope.() -> Unit,
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index fe05234..65c4043 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -17,12 +17,16 @@
package com.android.compose.animation.scene
import androidx.annotation.VisibleForTesting
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.key
+import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
@@ -253,6 +257,7 @@
key: OverlayKey,
userActions: Map<UserAction, UserActionResult>,
alignment: Alignment,
+ isModal: Boolean,
content: @Composable (ContentScope.() -> Unit),
) {
overlaysDefined = true
@@ -266,6 +271,7 @@
overlay.zIndex = zIndex
overlay.userActions = resolvedUserActions
overlay.alignment = alignment
+ overlay.isModal = isModal
} else {
// New overlay.
overlays[key] =
@@ -276,6 +282,7 @@
resolvedUserActions,
zIndex,
alignment,
+ isModal,
)
}
@@ -399,12 +406,30 @@
return
}
- // We put the overlays inside a Box that is matching the layout size so that overlays are
- // measured after all scenes and that their max size is the size of the layout without the
- // overlays.
- Box(Modifier.matchParentSize().zIndex(overlaysOrderedByZIndex.first().zIndex)) {
- overlaysOrderedByZIndex.fastForEach { overlay ->
- key(overlay.key) { overlay.Content(Modifier.align(overlay.alignment)) }
+ overlaysOrderedByZIndex.fastForEach { overlay ->
+ val key = overlay.key
+ key(key) {
+ // We put the overlays inside a Box that is matching the layout size so that they
+ // are measured after all scenes and that their max size is the size of the layout
+ // without the overlays.
+ Box(Modifier.matchParentSize().zIndex(overlay.zIndex)) {
+ if (overlay.isModal) {
+ // Add a fullscreen clickable to prevent swipes from reaching the scenes and
+ // other overlays behind this overlay. Clicking will close the overlay.
+ Box(
+ Modifier.fillMaxSize().clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = null,
+ ) {
+ if (state.canHideOverlay(key)) {
+ state.hideOverlay(key, animationScope = animationScope)
+ }
+ }
+ )
+ }
+
+ overlay.Content(Modifier.align(overlay.alignment))
+ }
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index dbff8a4..2e8fc14 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -176,6 +176,35 @@
animationScope: CoroutineScope,
transitionKey: TransitionKey? = null,
)
+
+ /**
+ * Instantly start a [transition], running it in [animationScope].
+ *
+ * This call returns immediately and [transition] will be the [currentTransition] of this
+ * [MutableSceneTransitionLayoutState].
+ *
+ * @see startTransition
+ */
+ fun startTransitionImmediately(
+ animationScope: CoroutineScope,
+ transition: TransitionState.Transition,
+ chain: Boolean = true,
+ ): Job
+
+ /**
+ * Start a new [transition].
+ *
+ * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
+ * will run in parallel to the current transitions. If [chain] is `false`, then the list of
+ * [currentTransitions] will be cleared and [transition] will be the only running transition.
+ *
+ * If any transition is currently ongoing, it will be interrupted and forced to animate to its
+ * current state by calling [TransitionState.Transition.freezeAndAnimateToCurrentState].
+ *
+ * This method returns when [transition] is done running, i.e. when the call to
+ * [run][TransitionState.Transition.run] returns.
+ */
+ suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean = true)
}
/**
@@ -313,18 +342,10 @@
)
}
- /**
- * Instantly start a [transition], running it in [animationScope].
- *
- * This call returns immediately and [transition] will be the [currentTransition] of this
- * [MutableSceneTransitionLayoutState].
- *
- * @see startTransition
- */
- internal fun startTransitionImmediately(
+ override fun startTransitionImmediately(
animationScope: CoroutineScope,
transition: TransitionState.Transition,
- chain: Boolean = true,
+ chain: Boolean,
): Job {
// Note that we start with UNDISPATCHED so that startTransition() is called directly and
// transition becomes the current [transitionState] right after this call.
@@ -333,23 +354,7 @@
}
}
- /**
- * Start a new [transition].
- *
- * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
- * will run in parallel to the current transitions. If [chain] is `false`, then the list of
- * [currentTransitions] will be cleared and [transition] will be the only running transition.
- *
- * If any transition is currently ongoing, it will be interrupted and forced to animate to its
- * current state.
- *
- * This method returns when [transition] is done running, i.e. when the call to
- * [run][TransitionState.Transition.run] returns.
- */
- internal suspend fun startTransition(
- transition: TransitionState.Transition,
- chain: Boolean = true,
- ) {
+ override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) {
checkThread()
try {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt
index ccec9e8..d4de559 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt
@@ -37,8 +37,10 @@
actions: Map<UserAction.Resolved, UserActionResult>,
zIndex: Float,
alignment: Alignment,
+ isModal: Boolean,
) : Content(key, layoutImpl, content, actions, zIndex) {
var alignment by mutableStateOf(alignment)
+ var isModal by mutableStateOf(isModal)
override fun toString(): String {
return "Overlay(key=$key)"
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index 364c203..d6751ae 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -300,7 +300,7 @@
}
/** Run this transition and return once it is finished. */
- internal abstract suspend fun run()
+ abstract suspend fun run()
/**
* Freeze this transition state so that neither [currentScene] nor [currentOverlays] will
@@ -311,7 +311,7 @@
*
* This is called when this transition is interrupted (replaced) by another transition.
*/
- internal abstract fun freezeAndAnimateToCurrentState()
+ abstract fun freezeAndAnimateToCurrentState()
internal fun updateOverscrollSpecs(
fromSpec: OverscrollSpecImpl?,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 20a1e3c..1eed54e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -52,6 +52,7 @@
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.hasParent
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
@@ -2488,4 +2489,95 @@
rule.waitForIdle()
return layoutImpl
}
+
+ @Test
+ fun elementComposableShouldPropagateMinConstraints() {
+ val contentTestTag = "content"
+ val movable = MovableElementKey("movable", contents = setOf(SceneA))
+ rule.setContent {
+ TestContentScope(currentScene = SceneA) {
+ Column {
+ Element(TestElements.Foo, Modifier.size(40.dp)) {
+ content {
+ // Modifier.size() sets a preferred size and this should be ignored
+ // because of the previously set 40dp size.
+ Box(Modifier.testTag(contentTestTag).size(20.dp))
+ }
+ }
+
+ MovableElement(movable, Modifier.size(40.dp)) {
+ content { Box(Modifier.testTag(contentTestTag).size(20.dp)) }
+ }
+ }
+ }
+ }
+
+ rule
+ .onNode(hasTestTag(contentTestTag) and hasParent(isElement(TestElements.Foo)))
+ .assertSizeIsEqualTo(40.dp)
+ rule
+ .onNode(hasTestTag(contentTestTag) and hasParent(isElement(movable)))
+ .assertSizeIsEqualTo(40.dp)
+ }
+
+ @Test
+ fun placeAllCopies() {
+ val foo = ElementKey("Foo", placeAllCopies = true)
+
+ @Composable
+ fun SceneScope.Foo(size: Dp, modifier: Modifier = Modifier) {
+ Box(modifier.element(foo).size(size))
+ }
+
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.size(100.dp)) { Foo(size = 10.dp) } },
+ toSceneContent = {
+ Box(Modifier.size(100.dp)) {
+ Foo(size = 50.dp, Modifier.align(Alignment.BottomEnd))
+ }
+ },
+ transition = { spec = tween(4 * 16, easing = LinearEasing) },
+ ) {
+ before {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(10.dp)
+ .assertPositionInRootIsEqualTo(0.dp, 0.dp)
+ onElement(foo, SceneB).assertDoesNotExist()
+ }
+
+ at(16) {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(20.dp)
+ .assertPositionInRootIsEqualTo(12.5.dp, 12.5.dp)
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(20.dp)
+ .assertPositionInRootIsEqualTo(12.5.dp, 12.5.dp)
+ }
+
+ at(32) {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(30.dp)
+ .assertPositionInRootIsEqualTo(25.dp, 25.dp)
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(30.dp)
+ .assertPositionInRootIsEqualTo(25.dp, 25.dp)
+ }
+
+ at(48) {
+ onElement(foo, SceneA)
+ .assertSizeIsEqualTo(40.dp)
+ .assertPositionInRootIsEqualTo(37.5.dp, 37.5.dp)
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(40.dp)
+ .assertPositionInRootIsEqualTo(37.5.dp, 37.5.dp)
+ }
+
+ after {
+ onElement(foo, SceneA).assertDoesNotExist()
+ onElement(foo, SceneB)
+ .assertSizeIsEqualTo(50.dp)
+ .assertPositionInRootIsEqualTo(50.dp, 50.dp)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index 7c9e9ce..e57702c 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -309,8 +309,10 @@
TestContentScope {
Element(TestElements.Foo, Modifier.size(200.dp)) {
content {
- Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
- Box(Modifier.testTag("matchParentSize").matchParentSize())
+ Box {
+ Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
+ Box(Modifier.testTag("matchParentSize").matchParentSize())
+ }
}
}
}
@@ -327,8 +329,10 @@
TestContentScope(currentScene = SceneA) {
MovableElement(key, Modifier.size(200.dp)) {
content {
- Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
- Box(Modifier.testTag("matchParentSize").matchParentSize())
+ Box {
+ Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
+ Box(Modifier.testTag("matchParentSize").matchParentSize())
+ }
}
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
index ffed15b..cae6617 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
@@ -18,10 +18,12 @@
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -31,19 +33,26 @@
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.click
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipe
+import androidx.compose.ui.test.swipeUp
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestOverlays.OverlayA
import com.android.compose.animation.scene.TestOverlays.OverlayB
import com.android.compose.animation.scene.TestScenes.SceneA
+import com.android.compose.animation.scene.subjects.assertThat
import com.android.compose.test.assertSizeIsEqualTo
import com.android.compose.test.setContentAndCreateMainScope
import com.android.compose.test.subjects.assertThat
@@ -769,4 +778,59 @@
.assertSizeIsEqualTo(100.dp)
.assertIsDisplayed()
}
+
+ @Test
+ fun overlaysAreModalByDefault() {
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ val scrollState = ScrollState(initial = 0)
+ val scope =
+ rule.setContentAndCreateMainScope {
+ SceneTransitionLayout(state) {
+ // Make the scene vertically scrollable.
+ scene(SceneA) {
+ Box(Modifier.size(200.dp).verticalScroll(scrollState)) {
+ Box(Modifier.size(200.dp, 400.dp))
+ }
+ }
+
+ // The overlay is at the center end of the scene.
+ overlay(OverlayA, alignment = Alignment.CenterEnd) {
+ Box(Modifier.size(100.dp))
+ }
+ }
+ }
+
+ fun swipeUp() {
+ rule.onRoot().performTouchInput {
+ swipe(start = Offset(x = 0f, y = bottom), end = Offset(x = 0f, y = top))
+ }
+ }
+
+ // Swiping up on the scene scrolls the list.
+ assertThat(scrollState.value).isEqualTo(0)
+ swipeUp()
+ assertThat(scrollState.value).isNotEqualTo(0)
+
+ // Reset the scroll.
+ scope.launch { scrollState.scrollTo(0) }
+ rule.waitForIdle()
+ assertThat(scrollState.value).isEqualTo(0)
+
+ // Show the overlay.
+ rule.runOnUiThread { state.showOverlay(OverlayA, animationScope = scope) }
+ rule.waitForIdle()
+ assertThat(state.transitionState).isIdle()
+ assertThat(state.transitionState).hasCurrentOverlays(OverlayA)
+
+ // Swiping up does not scroll the scene behind the overlay.
+ swipeUp()
+ assertThat(scrollState.value).isEqualTo(0)
+
+ // Clicking outside the overlay will close it.
+ rule.onRoot().performTouchInput { click(Offset.Zero) }
+ rule.waitForIdle()
+ assertThat(state.transitionState).isIdle()
+ assertThat(state.transitionState).hasCurrentOverlays(/* empty */ )
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
index de55e2f..ea6f208 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
@@ -31,16 +31,23 @@
import com.android.compose.animation.scene.TransitionRecordingSpec
import com.android.compose.animation.scene.featureOfElement
import com.android.compose.animation.scene.recordTransition
+import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.motion.compose.ComposeFeatureCaptures
import platform.test.motion.compose.createComposeMotionTestRule
import platform.test.motion.testing.createGoldenPathManager
+import platform.test.screenshot.ResetDeviceEmulationRule
@RunWith(AndroidJUnit4::class)
@MotionTest
class AnchoredSizeTest {
+
+ companion object {
+ @JvmField @ClassRule val cleanupRule: ResetDeviceEmulationRule = ResetDeviceEmulationRule()
+ }
+
private val goldenPaths =
createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index 062d351..a1d944b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -34,9 +34,11 @@
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.mock
@@ -86,6 +88,7 @@
@Mock private lateinit var postureController: DevicePostureController
@Mock private lateinit var mUserActivityNotifier: UserActivityNotifier
@Captor private lateinit var keyListenerArgumentCaptor: ArgumentCaptor<View.OnKeyListener>
+ private val kosmos = testKosmos()
private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
@@ -132,8 +135,8 @@
fakeFeatureFlags,
mSelectedUserInteractor,
keyguardKeyboardInteractor,
- null,
- mUserActivityNotifier
+ kosmos.bouncerHapticPlayer,
+ mUserActivityNotifier,
)
}
@@ -194,7 +197,7 @@
keyListenerArgumentCaptor.value.onKey(
keyguardPasswordView,
KeyEvent.KEYCODE_SPACE,
- KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE)
+ KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE),
)
assertFalse("Unlock attempted.", eventHandled)
@@ -213,7 +216,7 @@
keyListenerArgumentCaptor.value.onKey(
keyguardPasswordView,
KeyEvent.KEYCODE_ENTER,
- KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)
+ KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER),
)
assertTrue("Unlock not attempted.", eventHandled)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index bb15208..d63e728 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -30,7 +30,7 @@
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.haptics.msdl.msdlPlayer
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
@@ -92,7 +92,7 @@
@Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
private val kosmos = testKosmos()
- private val msdlPlayer = kosmos.msdlPlayer
+ private val bouncerHapticHelper = kosmos.bouncerHapticPlayer
@Before
fun setup() {
@@ -118,7 +118,7 @@
mPostureController,
fakeFeatureFlags,
mSelectedUserInteractor,
- msdlPlayer,
+ bouncerHapticHelper,
)
mKeyguardPatternView.onAttachedToWindow()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 1076d90..4d1660e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -34,10 +34,12 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
@@ -93,6 +95,9 @@
private KeyguardPinBasedInputViewController mKeyguardPinViewController;
+ private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this);
+ private BouncerHapticPlayer mBouncerHapticPlayer = mKosmosJavaAdapter.getBouncerHapticHelper();
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -119,7 +124,8 @@
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener,
mEmergencyButtonController, mFalsingCollector, featureFlags,
- mSelectedUserInteractor, keyguardKeyboardInteractor, null, mUserActivityNotifier) {
+ mSelectedUserInteractor, keyguardKeyboardInteractor, mBouncerHapticPlayer,
+ mUserActivityNotifier) {
@Override
public void onResume(int reason) {
super.onResume(reason);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
index 43db5a7..ab59051 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
@@ -50,6 +50,9 @@
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.FakeLogBuffer;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository;
@@ -66,8 +69,10 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -107,6 +112,8 @@
DreamOverlayStateController mDreamOverlayStateController;
@Mock
UserTracker mUserTracker;
+ @Mock
+ PrivacyItemController mPrivacyItemController;
LogBuffer mLogBuffer = FakeLogBuffer.Factory.Companion.create();
@@ -146,6 +153,7 @@
mDreamOverlayStateController,
mUserTracker,
mKosmos.getWifiInteractor(),
+ mPrivacyItemController,
mKosmos.getCommunalSceneInteractor(),
mLogBuffer);
mController.onInit();
@@ -160,6 +168,7 @@
verify(mDreamOverlayNotificationCountProvider).addCallback(any());
verify(mDreamOverlayStatusBarItemsProvider).addCallback(any());
verify(mDreamOverlayStateController).addCallback(any());
+ verify(mPrivacyItemController).addCallback(any());
}
@Test
@@ -172,6 +181,52 @@
}
@Test
+ public void testLocationIconShownWhenLocationActive() {
+ mController.onViewAttached();
+ final ArgumentCaptor<PrivacyItemController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(PrivacyItemController.Callback.class);
+ verify(mPrivacyItemController).addCallback(callbackCaptor.capture());
+
+ final PrivacyItem item = Mockito.mock(PrivacyItem.class);
+ when(item.getPrivacyType()).thenReturn(PrivacyType.TYPE_LOCATION);
+ callbackCaptor.getValue().onPrivacyItemsChanged(Arrays.asList(item));
+
+ verify(mView).showIcon(
+ eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+ }
+
+ @Test
+ public void testLocationIconNotShownForOtherPrivacyItems() {
+ mController.onViewAttached();
+ final ArgumentCaptor<PrivacyItemController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(PrivacyItemController.Callback.class);
+ verify(mPrivacyItemController).addCallback(callbackCaptor.capture());
+
+ final PrivacyItem item = Mockito.mock(PrivacyItem.class);
+ when(item.getPrivacyType()).thenReturn(PrivacyType.TYPE_CAMERA);
+ callbackCaptor.getValue().onPrivacyItemsChanged(Arrays.asList(item));
+
+ verify(mView, never()).showIcon(
+ eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+ }
+
+ @Test
+ public void testLocationIconNotShownForNoItems() {
+ mController.onViewAttached();
+ final ArgumentCaptor<PrivacyItemController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(PrivacyItemController.Callback.class);
+ verify(mPrivacyItemController).addCallback(callbackCaptor.capture());
+
+ verify(mView, never()).showIcon(
+ eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+
+ callbackCaptor.getValue().onPrivacyItemsChanged(Arrays.asList());
+
+ verify(mView, never()).showIcon(
+ eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+ }
+
+ @Test
public void testWifiIconHiddenWhenWifiAvailable() {
mController.onViewAttached();
mController.updateWifiUnavailableStatusIcon(true);
@@ -274,6 +329,7 @@
mDreamOverlayStateController,
mUserTracker,
mKosmos.getWifiInteractor(),
+ mPrivacyItemController,
mKosmos.getCommunalSceneInteractor(),
mLogBuffer);
controller.onViewAttached();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 8d82e97..2ee4aee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.bouncer.ui.viewmodel
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.view.KeyEvent.KEYCODE_0
import android.view.KeyEvent.KEYCODE_4
import android.view.KeyEvent.KEYCODE_A
@@ -31,6 +33,7 @@
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.data.repository.fakeSimBouncerRepository
+import com.android.systemui.classifier.fakeFalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
@@ -41,6 +44,7 @@
import com.google.common.truth.Truth.assertThat
import kotlin.random.Random
import kotlin.random.nextInt
+import kotlin.test.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
@@ -60,12 +64,13 @@
private val testScope = kosmos.testScope
private val sceneInteractor by lazy { kosmos.sceneInteractor }
private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
- private val underTest =
+ private val underTest by lazy {
kosmos.pinBouncerViewModelFactory.create(
isInputEnabled = MutableStateFlow(true),
onIntentionalUserInput = {},
authenticationMethod = AuthenticationMethodModel.Pin,
)
+ }
@Before
fun setUp() {
@@ -475,6 +480,18 @@
assertThat(pin).containsExactly(*expectedPin)
}
+ @Test
+ @EnableFlags(com.android.systemui.Flags.FLAG_COMPOSE_BOUNCER)
+ @DisableFlags(com.android.systemui.Flags.FLAG_SCENE_CONTAINER)
+ fun onDigitButtonDown_avoidGesture_invoked() =
+ testScope.runTest {
+ lockDeviceAndOpenPinBouncer()
+
+ underTest.onDigitButtonDown()
+
+ assertTrue(kosmos.fakeFalsingCollector.wasLastGestureAvoided())
+ }
+
private fun TestScope.switchToScene(toScene: SceneKey) {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 777ddab..b96e40f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -244,10 +244,7 @@
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
// Widgets available.
@@ -267,21 +264,14 @@
fun smartspaceDynamicSizing_oneCard_fullSize() =
testSmartspaceDynamicSizing(
totalTargets = 1,
- expectedSizes =
- listOf(
- CommunalContentSize.FULL,
- )
+ expectedSizes = listOf(CommunalContentSize.FULL),
)
@Test
fun smartspace_dynamicSizing_twoCards_halfSize() =
testSmartspaceDynamicSizing(
totalTargets = 2,
- expectedSizes =
- listOf(
- CommunalContentSize.HALF,
- CommunalContentSize.HALF,
- )
+ expectedSizes = listOf(CommunalContentSize.HALF, CommunalContentSize.HALF),
)
@Test
@@ -293,34 +283,34 @@
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ ),
)
@Test
- fun smartspace_dynamicSizing_fourCards_oneFullAndThreeThirdSize() =
+ fun smartspace_dynamicSizing_fourCards_threeThirdSizeAndOneFullSize() =
testSmartspaceDynamicSizing(
totalTargets = 4,
expectedSizes =
listOf(
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
CommunalContentSize.FULL,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- )
+ ),
)
@Test
- fun smartspace_dynamicSizing_fiveCards_twoHalfAndThreeThirdSize() =
+ fun smartspace_dynamicSizing_fiveCards_threeThirdAndTwoHalfSize() =
testSmartspaceDynamicSizing(
totalTargets = 5,
expectedSizes =
listOf(
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
CommunalContentSize.HALF,
CommunalContentSize.HALF,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- )
+ ),
)
@Test
@@ -335,7 +325,7 @@
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ ),
)
private fun testSmartspaceDynamicSizing(
@@ -355,7 +345,7 @@
smartspaceRepository.setTimers(targets)
- val smartspaceContent by collectLastValue(underTest.ongoingContent)
+ val smartspaceContent by collectLastValue(underTest.ongoingContent(false))
assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
for (index in 0 until totalTargets) {
assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
@@ -371,7 +361,7 @@
// Media is playing.
mediaRepository.mediaActive()
- val umoContent by collectLastValue(underTest.ongoingContent)
+ val umoContent by collectLastValue(underTest.ongoingContent(true))
assertThat(umoContent?.size).isEqualTo(1)
assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
@@ -379,6 +369,19 @@
}
@Test
+ fun umo_mediaPlaying_mediaHostNotVisible_hidesUmo() =
+ testScope.runTest {
+ // Tutorial completed.
+ tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+
+ // Media is playing.
+ mediaRepository.mediaActive()
+
+ val umoContent by collectLastValue(underTest.ongoingContent(false))
+ assertThat(umoContent?.size).isEqualTo(0)
+ }
+
+ @Test
fun ongoing_shouldOrderAndSizeByTimestamp() =
testScope.runTest {
// Keyguard showing, and tutorial completed.
@@ -401,19 +404,19 @@
val timer3 = smartspaceTimer("timer3", timestamp = 4L)
smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
- val ongoingContent by collectLastValue(underTest.ongoingContent)
+ val ongoingContent by collectLastValue(underTest.ongoingContent(true))
assertThat(ongoingContent?.size).isEqualTo(4)
assertThat(ongoingContent?.get(0)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
- assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.FULL)
+ assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(1)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer2"))
- assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(2)?.key).isEqualTo(CommunalContentModel.KEY.umo())
- assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(3)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer1"))
- assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.HALF)
}
@Test
@@ -435,10 +438,7 @@
testScope.runTest {
// Set to main user, so we can dismiss the tile for the main user.
val user = userRepository.asMainUser()
- userTracker.set(
- userInfos = listOf(user),
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
runCurrent()
tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
@@ -664,22 +664,31 @@
testScope.runTest {
// Verify default is false
val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
- runCurrent()
- assertThat(isCommunalShowing).isFalse()
-
- // Verify scene changes without the flag doesn't have any impact
- underTest.changeScene(CommunalScenes.Communal, "test")
- runCurrent()
assertThat(isCommunalShowing).isFalse()
// Verify scene changes (with the flag) to communal sets the value to true
sceneInteractor.changeScene(Scenes.Communal, loggingReason = "")
- runCurrent()
assertThat(isCommunalShowing).isTrue()
// Verify scene changes (with the flag) to lockscreen sets the value to false
sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "")
- runCurrent()
+ assertThat(isCommunalShowing).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun isCommunalShowing_whenSceneContainerEnabledAndChangeToLegacyScene() =
+ testScope.runTest {
+ // Verify default is false
+ val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
+ assertThat(isCommunalShowing).isFalse()
+
+ // Verify legacy scene change still makes communal show
+ underTest.changeScene(CommunalScenes.Communal, "test")
+ assertThat(isCommunalShowing).isTrue()
+
+ // Verify legacy scene change to blank makes communal hidden
+ underTest.changeScene(CommunalScenes.Blank, "test")
assertThat(isCommunalShowing).isFalse()
}
@@ -807,10 +816,7 @@
// Only main user exists.
val userInfos = listOf(MAIN_USER_INFO)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
val widgetContent by collectLastValue(underTest.widgetContent)
@@ -844,10 +850,7 @@
// Work profile is set up.
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
// When work profile is paused.
@@ -890,10 +893,7 @@
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
userRepository.setSelectedUserInfo(MAIN_USER_INFO)
runCurrent()
@@ -905,7 +905,7 @@
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
+ DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL,
)
// Widgets under work profile are filtered out. Only the regular widget remains.
@@ -923,10 +923,7 @@
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
userRepository.setSelectedUserInfo(MAIN_USER_INFO)
runCurrent()
@@ -938,7 +935,7 @@
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
+ DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE,
)
// Widgets under work profile are available.
@@ -958,7 +955,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -974,7 +971,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isFalse()
@@ -990,7 +987,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
runCurrent()
kosmos.setCommunalAvailable(false)
@@ -1008,13 +1005,13 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
runCurrent()
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.OCCLUDED,
to = KeyguardState.PRIMARY_BOUNCER,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -1030,7 +1027,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.DREAMING,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -1040,7 +1037,7 @@
return CommunalSmartspaceTimer(
smartspaceTargetId = id,
createdTimestampMillis = timestamp,
- remoteViews = mock(RemoteViews::class.java)
+ remoteViews = mock(RemoteViews::class.java),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
index dfb75ca..6a9b9be 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
@@ -16,18 +16,23 @@
package com.android.systemui.communal.domain.interactor
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.communal.data.repository.communalSceneRepository
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor.OnSceneAboutToChangeListener
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.andSceneContainer
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.initialSceneKey
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,10 +47,24 @@
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class CommunalSceneInteractorTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class CommunalSceneInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
@@ -53,6 +72,7 @@
private val repository = kosmos.communalSceneRepository
private val underTest by lazy { kosmos.communalSceneInteractor }
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun changeScene() =
testScope.runTest {
@@ -63,6 +83,7 @@
assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun changeScene_callsSceneStateProcessor() =
testScope.runTest {
@@ -78,6 +99,7 @@
verify(callback).onSceneAboutToChange(CommunalScenes.Communal, null)
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun changeScene_doesNotCallSceneStateProcessorForDuplicateState() =
testScope.runTest {
@@ -93,6 +115,7 @@
verify(callback, never()).onSceneAboutToChange(any(), anyOrNull())
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun snapToScene() =
testScope.runTest {
@@ -104,6 +127,7 @@
}
@OptIn(ExperimentalCoroutinesApi::class)
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun snapToSceneWithDelay() =
testScope.runTest {
@@ -119,30 +143,7 @@
assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
}
- @Test
- fun changeSceneForActivityStartOnDismissKeyguard() =
- testScope.runTest {
- val currentScene by collectLastValue(underTest.currentScene)
- underTest.snapToScene(CommunalScenes.Communal, "test")
- assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
-
- underTest.changeSceneForActivityStartOnDismissKeyguard()
- assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
- }
-
- @Test
- fun changeSceneForActivityStartOnDismissKeyguard_willNotChangeScene_forEditModeActivity() =
- testScope.runTest {
- val currentScene by collectLastValue(underTest.currentScene)
- underTest.snapToScene(CommunalScenes.Communal, "test")
- assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
-
- underTest.setEditModeState(EditModeState.STARTING)
-
- underTest.changeSceneForActivityStartOnDismissKeyguard()
- assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
- }
-
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun transitionProgress_fullProgress() =
testScope.runTest {
@@ -161,6 +162,7 @@
.isEqualTo(CommunalTransitionProgressModel.Idle(CommunalScenes.Communal))
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun transitionProgress_transitioningAwayFromTrackedScene() =
testScope.runTest {
@@ -201,6 +203,7 @@
.isEqualTo(CommunalTransitionProgressModel.Idle(CommunalScenes.Communal))
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun transitionProgress_transitioningToTrackedScene() =
testScope.runTest {
@@ -238,6 +241,7 @@
.isEqualTo(CommunalTransitionProgressModel.Idle(CommunalScenes.Communal))
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun isIdleOnCommunal() =
testScope.runTest {
@@ -265,6 +269,7 @@
assertThat(isIdleOnCommunal).isEqualTo(false)
}
+ @DisableFlags(FLAG_SCENE_CONTAINER)
@Test
fun isCommunalVisible() =
testScope.runTest {
@@ -304,4 +309,206 @@
)
assertThat(isCommunalVisible).isEqualTo(true)
}
+
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun changeScene_legacyCommunalScene_mapToStfScene() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+
+ // Verify that the current scene is the initial scene
+ assertThat(currentScene).isEqualTo(kosmos.initialSceneKey)
+
+ // Change to legacy communal scene
+ underTest.changeScene(CommunalScenes.Communal, loggingReason = "test")
+
+ // Verify that scene changed to communal scene in STF
+ assertThat(currentScene).isEqualTo(Scenes.Communal)
+
+ // Now change to legacy blank scene
+ underTest.changeScene(CommunalScenes.Blank, loggingReason = "test")
+
+ // Verify that scene changed to lock screen scene in STF
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun changeScene_stfScenes() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+
+ // Verify that the current scene is the initial scene
+ assertThat(currentScene).isEqualTo(kosmos.initialSceneKey)
+
+ // Change to communal scene
+ underTest.changeScene(Scenes.Communal, loggingReason = "test")
+
+ // Verify changed to communal scene
+ assertThat(currentScene).isEqualTo(Scenes.Communal)
+
+ // Now change to lockscreen scene
+ underTest.changeScene(Scenes.Lockscreen, loggingReason = "test")
+
+ // Verify changed to lockscreen scene
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun snapToScene_legacyCommunalScene_mapToStfScene() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+
+ // Verify that the current scene is the initial scene
+ assertThat(currentScene).isEqualTo(kosmos.initialSceneKey)
+
+ // Snap to legacy communal scene
+ underTest.snapToScene(CommunalScenes.Communal, loggingReason = "test")
+
+ // Verify that scene changed to communal scene in STF
+ assertThat(currentScene).isEqualTo(Scenes.Communal)
+
+ // Now snap to legacy blank scene
+ underTest.snapToScene(CommunalScenes.Blank, loggingReason = "test")
+
+ // Verify that scene changed to lock screen scene in STF
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun snapToScene_stfScenes() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+
+ // Verify that the current scene is the initial scene
+ assertThat(currentScene).isEqualTo(kosmos.initialSceneKey)
+
+ // Snap to communal scene
+ underTest.snapToScene(Scenes.Communal, loggingReason = "test")
+
+ // Verify changed to communal scene
+ assertThat(currentScene).isEqualTo(Scenes.Communal)
+
+ // Now snap to lockscreen scene
+ underTest.snapToScene(Scenes.Lockscreen, loggingReason = "test")
+
+ // Verify changed to lockscreen scene
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun isIdleOnCommunal_sceneContainerEnabled() =
+ testScope.runTest {
+ val transitionState: MutableStateFlow<ObservableTransitionState> =
+ MutableStateFlow(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ underTest.setTransitionState(transitionState)
+
+ // isIdleOnCommunal is initially false
+ val isIdleOnCommunal by collectLastValue(underTest.isIdleOnCommunal)
+ assertThat(isIdleOnCommunal).isEqualTo(false)
+
+ // Start transition to communal.
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Communal,
+ currentScene = flowOf(Scenes.Lockscreen),
+ progress = flowOf(0.1f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isIdleOnCommunal).isEqualTo(false)
+
+ // Finish transition to communal
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Communal)
+ assertThat(isIdleOnCommunal).isEqualTo(true)
+
+ // Start transition away from communal
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Communal,
+ toScene = Scenes.Lockscreen,
+ currentScene = flowOf(Scenes.Communal),
+ progress = flowOf(0.1f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isIdleOnCommunal).isEqualTo(false)
+
+ // Finish transition to lock screen
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ assertThat(isIdleOnCommunal).isEqualTo(false)
+ }
+
+ @EnableFlags(FLAG_SCENE_CONTAINER)
+ @Test
+ fun isCommunalVisible_sceneContainerEnabled() =
+ testScope.runTest {
+ val transitionState: MutableStateFlow<ObservableTransitionState> =
+ MutableStateFlow(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ underTest.setTransitionState(transitionState)
+
+ // isCommunalVisible is initially false
+ val isCommunalVisible by collectLastValue(underTest.isCommunalVisible)
+ assertThat(isCommunalVisible).isEqualTo(false)
+
+ // Start transition to communal.
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Communal,
+ currentScene = flowOf(Scenes.Lockscreen),
+ progress = flowOf(0.1f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isCommunalVisible).isEqualTo(true)
+
+ // Half-way transition to communal.
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Communal,
+ currentScene = flowOf(Scenes.Lockscreen),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isCommunalVisible).isEqualTo(true)
+
+ // Finish transition to communal
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Communal)
+ assertThat(isCommunalVisible).isEqualTo(true)
+
+ // Start transition away from communal
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Communal,
+ toScene = Scenes.Lockscreen,
+ currentScene = flowOf(Scenes.Communal),
+ progress = flowOf(0.1f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isCommunalVisible).isEqualTo(true)
+
+ // Half-way transition away from communal
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Communal,
+ toScene = Scenes.Lockscreen,
+ currentScene = flowOf(Scenes.Communal),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(isCommunalVisible).isEqualTo(true)
+
+ // Finish transition to lock screen
+ transitionState.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ assertThat(isCommunalVisible).isEqualTo(false)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
index b3a12a6..1e79112 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.widgets.CommunalAppWidgetHost
-import com.android.systemui.communal.widgets.CommunalAppWidgetHostView
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
@@ -61,29 +60,11 @@
context = context,
backgroundScope = kosmos.applicationCoroutineScope,
hostId = 116,
- interactionHandler = mock(),
- looper = testableLooper.looper,
logBuffer = logcatLogBuffer("CommunalAppWidgetHostTest"),
)
}
@Test
- fun createViewForCommunal_returnCommunalAppWidgetView() {
- val appWidgetId = 789
- val view =
- underTest.createViewForCommunal(
- context = context,
- appWidgetId = appWidgetId,
- appWidget = null
- )
- testableLooper.processAllMessages()
-
- assertThat(view).isInstanceOf(CommunalAppWidgetHostView::class.java)
- assertThat(view).isNotNull()
- assertThat(view.appWidgetId).isEqualTo(appWidgetId)
- }
-
- @Test
fun appWidgetIdToRemove_emit() =
testScope.runTest {
val appWidgetIdToRemove by collectLastValue(underTest.appWidgetIdToRemove)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 780d357..09daa51 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -43,6 +43,7 @@
import com.android.systemui.communal.domain.interactor.communalTutorialInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.log.CommunalMetricsLogger
+import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS
@@ -150,10 +151,7 @@
kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
- kosmos.fakeUserTracker.set(
- userInfos = listOf(MAIN_USER_INFO),
- selectedUserIndex = 0,
- )
+ kosmos.fakeUserTracker.set(userInfos = listOf(MAIN_USER_INFO), selectedUserIndex = 0)
whenever(mediaHost.visible).thenReturn(true)
kosmos.powerInteractor.setAwakeForTest()
@@ -249,6 +247,87 @@
}
@Test
+ fun ongoingContent_umoAndOneTimer_sizedAppropriately() =
+ testScope.runTest {
+ // Widgets available.
+ widgetRepository.addWidget(appWidgetId = 0, rank = 30)
+ widgetRepository.addWidget(appWidgetId = 1, rank = 20)
+
+ // Smartspace available.
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
+
+ // Media playing.
+ mediaRepository.mediaActive()
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // One timer, UMO, two widgets, and cta.
+ assertThat(communalContent?.size).isEqualTo(5)
+
+ val timer = communalContent?.get(0)
+ val umo = communalContent?.get(1)
+
+ assertThat(timer).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
+
+ assertThat(timer?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(umo?.size).isEqualTo(CommunalContentSize.HALF)
+ }
+
+ @Test
+ fun ongoingContent_umoAndTwoTimers_sizedAppropriately() =
+ testScope.runTest {
+ // Widgets available.
+ widgetRepository.addWidget(appWidgetId = 0, rank = 30)
+ widgetRepository.addWidget(appWidgetId = 1, rank = 20)
+
+ // Smartspace available.
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ ),
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ ),
+ )
+ )
+
+ // Media playing.
+ mediaRepository.mediaActive()
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // Two timers, UMO, two widgets, and cta.
+ assertThat(communalContent?.size).isEqualTo(6)
+
+ val timer1 = communalContent?.get(0)
+ val timer2 = communalContent?.get(1)
+ val umo = communalContent?.get(2)
+
+ assertThat(timer1).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(timer2).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
+
+ // One full-sized timer and a half-sized timer and half-sized UMO.
+ assertThat(timer1?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(timer2?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(umo?.size).isEqualTo(CommunalContentSize.FULL)
+ }
+
+ @Test
fun communalContent_mediaHostVisible_umoIncluded() =
testScope.runTest {
// Media playing.
@@ -497,7 +576,7 @@
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- )
+ ),
)
// Shade not expanded.
if (!SceneContainerFlag.isEnabled) shadeTestUtil.setLockscreenShadeExpansion(0f)
@@ -550,8 +629,8 @@
stateTransition =
TransitionStep(
from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ to = KeyguardState.GLANCEABLE_HUB
+ ),
)
// Then flow is not frozen
@@ -570,8 +649,8 @@
stateTransition =
TransitionStep(
from = KeyguardState.GLANCEABLE_HUB,
- to = KeyguardState.OCCLUDED,
- )
+ to = KeyguardState.OCCLUDED
+ ),
)
// Then flow is not frozen
@@ -595,7 +674,7 @@
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- )
+ ),
)
// Then flow is not frozen
@@ -614,7 +693,7 @@
to = KeyguardState.OCCLUDED,
transitionState = TransitionState.STARTED,
value = 0f,
- )
+ ),
)
// Then flow is frozen
@@ -629,7 +708,7 @@
to = KeyguardState.OCCLUDED,
transitionState = TransitionState.FINISHED,
value = 1f,
- )
+ ),
)
// Then flow is not frozen
@@ -658,8 +737,8 @@
stateTransition =
TransitionStep(
from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ to = KeyguardState.GLANCEABLE_HUB
+ ),
)
// Widgets available
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/OverlayWindowTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/OverlayWindowTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
index 3253edf..d90d58b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -19,6 +19,7 @@
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
@@ -42,11 +43,16 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.statusbar.sysuiStatusBarStateController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -66,10 +72,14 @@
private val trustRepository by lazy { kosmos.fakeTrustRepository }
private val sceneInteractor by lazy { kosmos.sceneInteractor }
private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
+ private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
+ private val sceneContainerStartable by lazy { kosmos.sceneContainerStartable }
+ private val sysuiStatusBarStateController by lazy { kosmos.sysuiStatusBarStateController }
private lateinit var underTest: DeviceEntryInteractor
@Before
fun setUp() {
+ sceneContainerStartable.start()
underTest = kosmos.deviceEntryInteractor
}
@@ -423,8 +433,37 @@
assertThat(isUnlocked).isTrue()
}
- private fun switchToScene(sceneKey: SceneKey) {
+ @Test
+ fun isDeviceEntered_unlockedWhileOnShade_emitsTrue() =
+ testScope.runTest {
+ val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ assertThat(isDeviceEntered).isFalse()
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ // Navigate to shade and bouncer:
+ switchToScene(Scenes.Shade)
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ // Simulating a "leave it open when the keyguard is hidden" which means the bouncer will
+ // be
+ // shown and successful authentication should take the user back to where they are, the
+ // shade scene.
+ sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
+ switchToScene(Scenes.Bouncer)
+ assertThat(currentScene).isEqualTo(Scenes.Bouncer)
+
+ assertThat(isDeviceEntered).isFalse()
+ // Authenticate with PIN to unlock and dismiss the lockscreen:
+ authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+ runCurrent()
+
+ assertThat(isDeviceEntered).isTrue()
+ }
+
+ private fun TestScope.switchToScene(sceneKey: SceneKey) {
sceneInteractor.changeScene(sceneKey, "reason")
+ sceneInteractor.setTransitionState(flowOf(ObservableTransitionState.Idle(sceneKey)))
+ runCurrent()
}
private suspend fun givenCanShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationUtil.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationUtil.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeDockHandlerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeDockHandlerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeServiceFake.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeServiceFake.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuppressorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuppressorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeUiTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeUiTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
index 25c5336..64915fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
@@ -261,12 +261,12 @@
.registerKeyGestureEventListener(any(), listenerCaptor.capture())
val allAppsKeyGestureEvent =
- KeyGestureEvent(
- /* deviceId= */ 1,
- IntArray(0),
- KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
- )
+ KeyGestureEvent.Builder()
+ .setDeviceId(1)
+ .setModifierState(KeyEvent.META_META_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ .build()
listenerCaptor.value.onKeyGestureEvent(allAppsKeyGestureEvent)
val model by
diff --git a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/emergency/EmergencyActivityTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/emergency/EmergencyActivityTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagCommandTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagCommandTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagDependenciesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagDependenciesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/PluggedInConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/PluggedInConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/fragments/FragmentServiceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/fragments/FragmentServiceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ShutdownUiTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ShutdownUiTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 1981a2d..41cc953 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
@@ -39,8 +39,6 @@
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.testKosmos
@@ -79,12 +77,9 @@
dismissInteractor = dismissInteractor,
applicationScope = testScope.backgroundScope,
sceneInteractor = { kosmos.sceneInteractor },
- deviceEntryInteractor = { kosmos.deviceEntryInteractor },
- quickSettingsSceneFamilyResolver = { kosmos.quickSettingsSceneFamilyResolver },
- notifShadeSceneFamilyResolver = { kosmos.notifShadeSceneFamilyResolver },
+ deviceUnlockedInteractor = { kosmos.deviceUnlockedInteractor },
powerInteractor = kosmos.powerInteractor,
alternateBouncerInteractor = kosmos.alternateBouncerInteractor,
- keyguardInteractor = { kosmos.keyguardInteractor },
shadeInteractor = { kosmos.shadeInteractor },
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 3b2b12c..2fd94e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -335,6 +335,7 @@
}
@Test
+ @DisableSceneContainer
fun alpha_idleOnHub_isZero() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha(viewState))
@@ -506,6 +507,46 @@
@Test
@DisableSceneContainer
+ fun alphaFromShadeExpansion_doesNotEmitWhenOccludedTransitionRunning() =
+ testScope.runTest {
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ testScope,
+ )
+
+ val alpha by collectLastValue(underTest.alpha(viewState))
+ shadeTestUtil.setQsExpansion(0f)
+ runCurrent()
+ assertThat(alpha).isEqualTo(1f)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ transitionState = TransitionState.STARTED,
+ value = 0f,
+ ),
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ transitionState = TransitionState.RUNNING,
+ value = 0.8f,
+ ),
+ ),
+ testScope,
+ )
+ // Alpha should be 0f from the above transition
+ assertThat(alpha).isEqualTo(0f)
+
+ shadeTestUtil.setQsExpansion(0.5f)
+ // Alpha should remain unchanged
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ @DisableSceneContainer
fun alphaFromShadeExpansion_doesNotEmitWhenLockscreenToDreamTransitionRunning() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/SessionTrackerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/SessionTrackerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/core/LoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/core/LoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/core/LoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/core/LoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/FakeLogProxy.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/FakeLogProxy.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/TableChangeTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/TableChangeTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestUtils.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestUtils.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
index f6865f13..642d9a0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -28,6 +29,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayActionsViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -47,7 +49,7 @@
private val underTest = kosmos.notificationsShadeOverlayActionsViewModel
@Test
- fun upTransitionSceneKey_hidesShade() =
+ fun up_hidesShade() =
testScope.runTest {
val actions by collectLastValue(underTest.actions)
underTest.activateIn(this)
@@ -66,4 +68,22 @@
assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
.isEqualTo(Overlays.NotificationsShade)
}
+
+ @Test
+ fun downFromTopRight_switchesToQuickSettingsShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ underTest.activateIn(this)
+
+ assertThat(
+ (actions?.get(
+ Swipe(
+ direction = SwipeDirection.Down,
+ fromSource = SceneContainerEdge.TopRight,
+ )
+ ) as? UserActionResult.ReplaceByOverlay)
+ ?.overlay
+ )
+ .isEqualTo(Overlays.QuickSettingsShade)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
index b54fd86..75b090c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor
-import android.platform.test.annotations.EnabledOnRavenwood
import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.CheckFlagsRule
@@ -46,7 +45,6 @@
import org.mockito.kotlin.verify
@SmallTest
-@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
index 762941d..fd1c043 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -28,6 +29,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -46,7 +48,7 @@
private val underTest = kosmos.quickSettingsShadeOverlayActionsViewModel
@Test
- fun upTransitionSceneKey_hidesShade() =
+ fun up_hidesShade() =
testScope.runTest {
val actions by collectLastValue(underTest.actions)
underTest.activateIn(this)
@@ -57,12 +59,44 @@
}
@Test
- fun back_hidesShade() =
+ fun back_notEditing_hidesShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ val isEditing by
+ collectLastValue(kosmos.quickSettingsContainerViewModel.editModeViewModel.isEditing)
+ underTest.activateIn(this)
+ assertThat(isEditing).isFalse()
+
+ assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
+ .isEqualTo(Overlays.QuickSettingsShade)
+ }
+
+ @Test
+ fun back_whileEditing_doesNotHideShade() =
testScope.runTest {
val actions by collectLastValue(underTest.actions)
underTest.activateIn(this)
- assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
- .isEqualTo(Overlays.QuickSettingsShade)
+ kosmos.quickSettingsContainerViewModel.editModeViewModel.startEditing()
+
+ assertThat(actions?.get(Back)).isNull()
+ }
+
+ @Test
+ fun downFromTopLeft_switchesToNotificationsShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ underTest.activateIn(this)
+
+ assertThat(
+ (actions?.get(
+ Swipe(
+ direction = SwipeDirection.Down,
+ fromSource = SceneContainerEdge.TopLeft,
+ )
+ ) as? UserActionResult.ReplaceByOverlay)
+ ?.overlay
+ )
+ .isEqualTo(Overlays.NotificationsShade)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
index 6986cf8e..62b6391 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
@@ -37,7 +37,6 @@
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
-import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -46,7 +45,6 @@
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -61,7 +59,7 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private val qsFlexiglassAdapter = FakeQSSceneAdapter({ mock() })
+ private val qsFlexiglassAdapter = kosmos.fakeQsSceneAdapter
private val sceneInteractor = kosmos.sceneInteractor
private val sceneBackInteractor = kosmos.sceneBackInteractor
@@ -101,10 +99,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Gone)
@@ -130,10 +126,8 @@
mapOf(
Back to UserActionResult(Scenes.Lockscreen),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Lockscreen)
@@ -161,10 +155,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Gone)
@@ -187,10 +179,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Lockscreen)
@@ -225,10 +215,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Gone)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 2d42c42..a0cafcb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -161,9 +161,7 @@
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
- kosmos.emulateUserDrivenTransition(
- to = upDestinationSceneKey,
- )
+ kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
kosmos.fakeSceneDataSource.pause()
kosmos.enterPin()
@@ -226,16 +224,14 @@
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home)
assertThat(homeScene).isEqualTo(Scenes.Gone)
- kosmos.emulateUserDrivenTransition(
- to = homeScene,
- )
+ kosmos.emulateUserDrivenTransition(to = homeScene)
}
@Test
fun withAuthMethodNone_deviceWakeUp_skipsLockscreen() =
testScope.runTest {
kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = false)
- kosmos.putDeviceToSleep(instantlyLockDevice = false)
+ kosmos.putDeviceToSleep()
kosmos.assertCurrentScene(Scenes.Lockscreen)
kosmos.wakeUpDevice()
@@ -246,7 +242,7 @@
fun withAuthMethodSwipe_deviceWakeUp_doesNotSkipLockscreen() =
testScope.runTest {
kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
- kosmos.putDeviceToSleep(instantlyLockDevice = false)
+ kosmos.putDeviceToSleep()
kosmos.assertCurrentScene(Scenes.Lockscreen)
kosmos.wakeUpDevice()
@@ -302,7 +298,7 @@
testScope.runTest {
kosmos.unlockDevice()
kosmos.assertCurrentScene(Scenes.Gone)
- kosmos.putDeviceToSleep(instantlyLockDevice = false)
+ kosmos.putDeviceToSleep()
kosmos.assertCurrentScene(Scenes.Lockscreen)
// Pretend like the timeout elapsed and now lock the device.
@@ -318,9 +314,7 @@
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
- kosmos.emulateUserDrivenTransition(
- to = upDestinationSceneKey,
- )
+ kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
kosmos.fakeSceneDataSource.pause()
kosmos.dismissIme()
@@ -388,7 +382,7 @@
kosmos.emulatePendingTransitionProgress(expectedVisible = true)
kosmos.enterSimPin(
authMethodAfterSimUnlock = AuthenticationMethodModel.None,
- enableLockscreen = false
+ enableLockscreen = false,
)
kosmos.assertCurrentScene(Scenes.Gone)
@@ -434,7 +428,7 @@
/** Updates the current authentication method and related states in the data layer. */
private fun Kosmos.setAuthMethod(
authMethod: AuthenticationMethodModel,
- enableLockscreen: Boolean = true
+ enableLockscreen: Boolean = true,
) {
if (authMethod.isSecure) {
assert(enableLockscreen) {
@@ -538,24 +532,27 @@
kosmos.fakeSceneDataSource.pause()
sceneInteractor.changeScene(to, "reason")
- emulatePendingTransitionProgress(
- expectedVisible = to != Scenes.Gone,
- )
+ emulatePendingTransitionProgress(expectedVisible = to != Scenes.Gone)
}
/**
- * Locks the device immediately (without delay).
+ * Locks the device.
*
* Asserts the device to be lockable (e.g. that the current authentication is secure).
*
- * Not to be confused with [putDeviceToSleep], which may also instantly lock the device.
+ * Internally emulates a power button press that puts the device to sleep, followed by another
+ * power button press that wakes up the device but is then expected to be in the locked state.
*/
private suspend fun Kosmos.lockDevice() {
val authMethod = authenticationInteractor.getAuthenticationMethod()
assertWithMessage("The authentication method of $authMethod is not secure, cannot lock!")
.that(authMethod.isSecure)
.isTrue()
- sceneInteractor.changeScene(Scenes.Lockscreen, "")
+
+ powerInteractor.setAsleepForTest()
+ testScope.runCurrent()
+
+ powerInteractor.setAwakeForTest()
testScope.runCurrent()
}
@@ -569,9 +566,7 @@
fakeSceneDataSource.pause()
enterPin()
- emulatePendingTransitionProgress(
- expectedVisible = false,
- )
+ emulatePendingTransitionProgress(expectedVisible = false)
}
/**
@@ -645,9 +640,7 @@
}
/** Changes device wakefulness state from awake to asleep, going through intermediary states. */
- private suspend fun Kosmos.putDeviceToSleep(
- instantlyLockDevice: Boolean = true,
- ) {
+ private suspend fun Kosmos.putDeviceToSleep() {
val wakefulnessModel = powerInteractor.detailedWakefulness.value
assertWithMessage("Cannot put device to sleep as it's already asleep!")
.that(wakefulnessModel.isAwake())
@@ -655,10 +648,6 @@
powerInteractor.setAsleepForTest()
testScope.runCurrent()
-
- if (instantlyLockDevice) {
- lockDevice()
- }
}
/** Emulates the dismissal of the IME (soft keyboard). */
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
index 1f3454d..405cfd3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
@@ -28,6 +28,8 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.sceneStackOf
import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
@@ -173,12 +175,32 @@
)
}
+ @Test
+ @EnableSceneContainer
+ fun updateBackStack() =
+ testScope.runTest {
+ underTest.onSceneChange(from = Scenes.Lockscreen, to = Scenes.Shade)
+ underTest.onSceneChange(from = Scenes.Shade, to = Scenes.QuickSettings)
+ underTest.onSceneChange(from = Scenes.QuickSettings, to = Scenes.Bouncer)
+ assertThat(underTest.backStack.value.asIterable().toList())
+ .isEqualTo(listOf(Scenes.QuickSettings, Scenes.Shade, Scenes.Lockscreen))
+
+ underTest.updateBackStack { stack ->
+ // Reverse the stack, just to see if it can be done:
+ sceneStackOf(*stack.asIterable().reversed().toTypedArray())
+ }
+
+ assertThat(underTest.backStack.value.asIterable().toList())
+ .isEqualTo(listOf(Scenes.Lockscreen, Scenes.Shade, Scenes.QuickSettings))
+ }
+
private suspend fun TestScope.assertRoute(vararg route: RouteNode) {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val backScene by collectLastValue(underTest.backScene)
route.forEachIndexed { index, node ->
sceneInteractor.changeScene(node.changeSceneTo, "")
+ runCurrent()
assertWithMessage("node at index $index currentScene mismatch")
.that(currentScene)
.isEqualTo(node.changeSceneTo)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
index edaa3d3..bf97afe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
@@ -18,9 +18,12 @@
package com.android.systemui.scene.domain.interactor
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ShowOrHideOverlay
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -29,8 +32,10 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.sceneDataSource
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
@@ -63,10 +68,11 @@
private val sceneDataSource =
kosmos.sceneDataSource.apply { changeScene(toScene = Scenes.Lockscreen) }
- private val underTest = kosmos.sceneContainerOcclusionInteractor
+ private val underTest by lazy { kosmos.sceneContainerOcclusionInteractor }
@Test
- fun invisibleDueToOcclusion() =
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun invisibleDueToOcclusion_dualShadeDisabled() =
testScope.runTest {
val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion)
val keyguardState by collectLastValue(keyguardTransitionInteractor.currentKeyguardState)
@@ -126,6 +132,68 @@
.isFalse()
}
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun invisibleDueToOcclusion_dualShadeEnabled() =
+ testScope.runTest {
+ val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion)
+ val keyguardState by collectLastValue(keyguardTransitionInteractor.currentKeyguardState)
+
+ // Assert that we have the desired preconditions:
+ assertThat(keyguardState).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
+ assertThat(sceneInteractor.transitionState.value)
+ .isEqualTo(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ assertWithMessage("Should start unoccluded").that(invisibleDueToOcclusion).isFalse()
+
+ // Actual testing starts here:
+ showOccludingActivity()
+ assertWithMessage("Should become occluded when occluding activity is shown")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+
+ transitionIntoAod {
+ assertWithMessage("Should become unoccluded when transitioning into AOD")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should stay unoccluded when in AOD")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+
+ transitionOutOfAod {
+ assertWithMessage("Should remain unoccluded while transitioning away from AOD")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should become occluded now that no longer in AOD")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+
+ expandDualShade {
+ assertWithMessage("Should become unoccluded once shade begins to expand")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should be unoccluded when shade is fully expanded")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+
+ collapseDualShade {
+ assertWithMessage("Should remain unoccluded while shade is collapsing")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should become occluded now that shade is fully collapsed")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+
+ hideOccludingActivity()
+ assertWithMessage("Should become unoccluded once the occluding activity is hidden")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+
/** Simulates the appearance of a show-when-locked `Activity` in the foreground. */
private fun TestScope.showOccludingActivity() {
keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
@@ -138,15 +206,13 @@
/** Simulates the disappearance of a show-when-locked `Activity` from the foreground. */
private fun TestScope.hideOccludingActivity() {
keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
- showWhenLockedActivityOnTop = false,
+ showWhenLockedActivityOnTop = false
)
runCurrent()
}
/** Simulates a user-driven gradual expansion of the shade. */
- private fun TestScope.expandShade(
- assertMidTransition: () -> Unit = {},
- ) {
+ private fun TestScope.expandShade(assertMidTransition: () -> Unit = {}) {
val progress = MutableStateFlow(0f)
mutableTransitionState.value =
ObservableTransitionState.Transition(
@@ -170,10 +236,41 @@
runCurrent()
}
+ /** Simulates a user-driven gradual expansion of the dual shade (notifications). */
+ private fun TestScope.expandDualShade(assertMidTransition: () -> Unit = {}) {
+ val progress = MutableStateFlow(0f)
+ mutableTransitionState.value =
+ ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = sceneDataSource.currentScene.value,
+ toContent = Overlays.NotificationsShade,
+ currentScene = sceneDataSource.currentScene.value,
+ currentOverlays = sceneDataSource.currentOverlays,
+ progress = progress,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ runCurrent()
+
+ progress.value = 0.5f
+ runCurrent()
+ assertMidTransition()
+
+ progress.value = 1f
+ runCurrent()
+
+ mutableTransitionState.value =
+ ObservableTransitionState.Idle(
+ sceneDataSource.currentScene.value,
+ setOf(Overlays.NotificationsShade),
+ )
+ runCurrent()
+ }
+
/** Simulates a user-driven gradual collapse of the shade. */
- private fun TestScope.collapseShade(
- assertMidTransition: () -> Unit = {},
- ) {
+ private fun TestScope.collapseShade(assertMidTransition: () -> Unit = {}) {
val progress = MutableStateFlow(0f)
mutableTransitionState.value =
ObservableTransitionState.Transition(
@@ -197,10 +294,37 @@
runCurrent()
}
+ /** Simulates a user-driven gradual collapse of the dual shade (notifications). */
+ private fun TestScope.collapseDualShade(assertMidTransition: () -> Unit = {}) {
+ val progress = MutableStateFlow(0f)
+ mutableTransitionState.value =
+ ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = Overlays.NotificationsShade,
+ toContent = Scenes.Lockscreen,
+ currentScene = Scenes.Lockscreen,
+ currentOverlays = flowOf(setOf(Overlays.NotificationsShade)),
+ progress = progress,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ runCurrent()
+
+ progress.value = 0.5f
+ runCurrent()
+ assertMidTransition()
+
+ progress.value = 1f
+ runCurrent()
+
+ mutableTransitionState.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ runCurrent()
+ }
+
/** Simulates a transition into AOD. */
- private suspend fun TestScope.transitionIntoAod(
- assertMidTransition: () -> Unit = {},
- ) {
+ private suspend fun TestScope.transitionIntoAod(assertMidTransition: () -> Unit = {}) {
val currentKeyguardState = keyguardTransitionInteractor.getCurrentState()
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -235,9 +359,7 @@
}
/** Simulates a transition away from AOD. */
- private suspend fun TestScope.transitionOutOfAod(
- assertMidTransition: () -> Unit = {},
- ) {
+ private suspend fun TestScope.transitionOutOfAod(assertMidTransition: () -> Unit = {}) {
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.AOD,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 4a7d8b0..7fe3d8d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -21,6 +21,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ShowOrHideOverlay
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -38,6 +39,7 @@
import com.android.systemui.scene.overlayKeys
import com.android.systemui.scene.sceneContainerConfig
import com.android.systemui.scene.sceneKeys
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
@@ -256,7 +258,7 @@
}
@Test
- fun transitioningTo() =
+ fun transitioningTo_sceneChange() =
testScope.runTest {
val transitionState =
MutableStateFlow<ObservableTransitionState>(
@@ -293,6 +295,51 @@
}
@Test
+ fun transitioningTo_overlayChange() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(underTest.currentScene.value)
+ )
+ underTest.setTransitionState(transitionState)
+
+ val transitionTo by collectLastValue(underTest.transitioningTo)
+ assertThat(transitionTo).isNull()
+
+ underTest.showOverlay(Overlays.NotificationsShade, "reason")
+ assertThat(transitionTo).isNull()
+
+ val progress = MutableStateFlow(0f)
+ transitionState.value =
+ ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = underTest.currentScene.value,
+ toContent = Overlays.NotificationsShade,
+ currentScene = underTest.currentScene.value,
+ currentOverlays = underTest.currentOverlays,
+ progress = progress,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ assertThat(transitionTo).isEqualTo(Overlays.NotificationsShade)
+
+ progress.value = 0.5f
+ assertThat(transitionTo).isEqualTo(Overlays.NotificationsShade)
+
+ progress.value = 1f
+ assertThat(transitionTo).isEqualTo(Overlays.NotificationsShade)
+
+ transitionState.value =
+ ObservableTransitionState.Idle(
+ currentScene = underTest.currentScene.value,
+ currentOverlays = setOf(Overlays.NotificationsShade),
+ )
+ assertThat(transitionTo).isNull()
+ }
+
+ @Test
fun isTransitionUserInputOngoing_idle_false() =
testScope.runTest {
val transitionState =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index d180460..763a1a9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -33,7 +33,9 @@
import com.android.keyguard.AuthInteractionProperties
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
@@ -82,7 +84,9 @@
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
@@ -131,6 +135,7 @@
private val testScope = kosmos.testScope
private val deviceEntryHapticsInteractor by lazy { kosmos.deviceEntryHapticsInteractor }
private val sceneInteractor by lazy { kosmos.sceneInteractor }
+ private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository }
private val bouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
@@ -237,17 +242,14 @@
fun hydrateVisibility_basedOnOcclusion() =
testScope.runTest {
val isVisible by collectLastValue(sceneInteractor.isVisible)
- prepareState(
- isDeviceUnlocked = true,
- initialSceneKey = Scenes.Lockscreen,
- )
+ prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Lockscreen)
underTest.start()
assertThat(isVisible).isTrue()
kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
true,
- mock()
+ mock(),
)
assertThat(isVisible).isFalse()
@@ -259,10 +261,7 @@
fun hydrateVisibility_basedOnAlternateBouncer() =
testScope.runTest {
val isVisible by collectLastValue(sceneInteractor.isVisible)
- prepareState(
- isDeviceUnlocked = false,
- initialSceneKey = Scenes.Lockscreen,
- )
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Lockscreen)
underTest.start()
assertThat(isVisible).isTrue()
@@ -270,7 +269,7 @@
// WHEN the device is occluded,
kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
true,
- mock()
+ mock(),
)
// THEN scenes are not visible
assertThat(isVisible).isFalse()
@@ -393,6 +392,7 @@
fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val backStack by collectLastValue(sceneBackInteractor.backStack)
kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open
val transitionState =
@@ -414,12 +414,14 @@
transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer)
runCurrent()
assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
+ assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Lockscreen)
kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
SuccessFingerprintAuthenticationStatus(0, true)
)
assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings)
+ assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Gone)
}
@Test
@@ -478,10 +480,7 @@
fun stayOnLockscreenWhenDeviceUnlocksWithBypassOff() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
- prepareState(
- isBypassEnabled = false,
- initialSceneKey = Scenes.Lockscreen,
- )
+ prepareState(isBypassEnabled = false, initialSceneKey = Scenes.Lockscreen)
assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
underTest.start()
@@ -520,10 +519,7 @@
fun switchToGoneWhenDeviceIsUnlockedAndUserIsOnBouncerWithBypassDisabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
- prepareState(
- isBypassEnabled = false,
- initialSceneKey = Scenes.Bouncer,
- )
+ prepareState(isBypassEnabled = false, initialSceneKey = Scenes.Bouncer)
assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
underTest.start()
@@ -539,10 +535,7 @@
val alternateBouncerVisible by
collectLastValue(bouncerRepository.alternateBouncerVisible)
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
- prepareState(
- isDeviceUnlocked = false,
- initialSceneKey = Scenes.Shade,
- )
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
bouncerRepository.setAlternateVisible(true)
underTest.start()
@@ -564,10 +557,7 @@
fun switchToLockscreenWhenDeviceSleepsLocked() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
- prepareState(
- isDeviceUnlocked = false,
- initialSceneKey = Scenes.Shade,
- )
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
underTest.start()
powerInteractor.setAsleepForTest()
@@ -583,10 +573,7 @@
val currentTransitionInfo by
collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
val transitionState =
- prepareState(
- isDeviceUnlocked = false,
- initialSceneKey = Scenes.Shade,
- )
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
kosmos.keyguardRepository.setAodAvailable(true)
runCurrent()
assertThat(asleepState).isEqualTo(KeyguardState.AOD)
@@ -615,10 +602,7 @@
val currentTransitionInfo by
collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
val transitionState =
- prepareState(
- isDeviceUnlocked = false,
- initialSceneKey = Scenes.Shade,
- )
+ prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
kosmos.keyguardRepository.setAodAvailable(false)
runCurrent()
assertThat(asleepState).isEqualTo(KeyguardState.DOZING)
@@ -1078,16 +1062,14 @@
@Test
fun hydrateSystemUiState_onLockscreen_basedOnOcclusion() =
testScope.runTest {
- prepareState(
- initialSceneKey = Scenes.Lockscreen,
- )
+ prepareState(initialSceneKey = Scenes.Lockscreen)
underTest.start()
runCurrent()
clearInvocations(sysUiState)
kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
true,
- mock()
+ mock(),
)
runCurrent()
assertThat(
@@ -1210,7 +1192,7 @@
initialSceneKey = Scenes.Lockscreen,
authenticationMethod = AuthenticationMethodModel.Pin,
isDeviceUnlocked = false,
- startsAwake = false
+ startsAwake = false,
)
assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
underTest.start()
@@ -1228,11 +1210,14 @@
@Test
fun collectFalsingSignals_onSuccessfulUnlock() =
testScope.runTest {
- prepareState(
- initialSceneKey = Scenes.Lockscreen,
- authenticationMethod = AuthenticationMethodModel.Pin,
- isDeviceUnlocked = false,
- )
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+
+ val transitionStateFlow =
+ prepareState(
+ initialSceneKey = Scenes.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ isDeviceUnlocked = false,
+ )
underTest.start()
runCurrent()
verify(falsingCollector, never()).onSuccessfulUnlock()
@@ -1247,36 +1232,46 @@
)
.forEach { sceneKey ->
sceneInteractor.changeScene(sceneKey, "reason")
+ transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
runCurrent()
verify(falsingCollector, never()).onSuccessfulUnlock()
}
// Changing to the Gone scene should report a successful unlock.
- kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
- SuccessFingerprintAuthenticationStatus(0, true)
- )
+ kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
runCurrent()
- sceneInteractor.changeScene(Scenes.Gone, "reason")
+ // Make sure that the startable changed the scene to Gone because the device unlocked.
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ // Make the transition state match the current state
+ transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
runCurrent()
verify(falsingCollector).onSuccessfulUnlock()
// Move around scenes without changing back to Lockscreen, shouldn't report another
// unlock.
- listOf(
- Scenes.Shade,
- Scenes.QuickSettings,
- Scenes.Shade,
- Scenes.Gone,
- )
- .forEach { sceneKey ->
- sceneInteractor.changeScene(sceneKey, "reason")
- runCurrent()
- verify(falsingCollector, times(1)).onSuccessfulUnlock()
- }
+ listOf(Scenes.Shade, Scenes.QuickSettings, Scenes.Shade, Scenes.Gone).forEach { sceneKey
+ ->
+ sceneInteractor.changeScene(sceneKey, "reason")
+ transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
+ runCurrent()
+ verify(falsingCollector, times(1)).onSuccessfulUnlock()
+ }
- // Changing to the Lockscreen scene shouldn't report a successful unlock.
- sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+ // Putting the device to sleep to lock it again, which shouldn't report another
+ // successful unlock.
+ kosmos.powerInteractor.setAsleepForTest()
runCurrent()
+ // Verify that the startable changed the scene to Lockscreen because the device locked
+ // following the sleep.
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ // Make the transition state match the current state
+ transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ // Wake up the device again before continuing with the test.
+ kosmos.powerInteractor.setAwakeForTest()
+ runCurrent()
+ // Verify that the current scene is still the Lockscreen scene, now that the device is
+ // still locked.
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
verify(falsingCollector, times(1)).onSuccessfulUnlock()
// Move around scenes without unlocking.
@@ -1289,12 +1284,17 @@
)
.forEach { sceneKey ->
sceneInteractor.changeScene(sceneKey, "reason")
+ transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
runCurrent()
verify(falsingCollector, times(1)).onSuccessfulUnlock()
}
- // Changing to the Gone scene should report a second successful unlock.
- sceneInteractor.changeScene(Scenes.Gone, "reason")
+ kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+ runCurrent()
+ // Make sure that the startable changed the scene to Gone because the device unlocked.
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ // Make the transition state match the current scene.
+ transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
runCurrent()
verify(falsingCollector, times(2)).onSuccessfulUnlock()
}
@@ -1608,7 +1608,7 @@
kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
true,
- mock()
+ mock(),
)
runCurrent()
verify(notificationShadeWindowController, times(1)).setKeyguardOccluded(true)
@@ -1623,10 +1623,7 @@
@Test
fun hydrateInteractionState_whileLocked() =
testScope.runTest {
- val transitionStateFlow =
- prepareState(
- initialSceneKey = Scenes.Lockscreen,
- )
+ val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen)
underTest.start()
runCurrent()
verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
@@ -1643,10 +1640,7 @@
},
verifyAfterTransition = {
verify(centralSurfaces)
- .setInteracting(
- StatusBarManager.WINDOW_STATUS_BAR,
- false,
- )
+ .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false)
},
)
@@ -1661,11 +1655,7 @@
verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
},
verifyAfterTransition = {
- verify(centralSurfaces)
- .setInteracting(
- StatusBarManager.WINDOW_STATUS_BAR,
- true,
- )
+ verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
},
)
@@ -1681,10 +1671,7 @@
},
verifyAfterTransition = {
verify(centralSurfaces)
- .setInteracting(
- StatusBarManager.WINDOW_STATUS_BAR,
- false,
- )
+ .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false)
},
)
@@ -1699,11 +1686,7 @@
verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
},
verifyAfterTransition = {
- verify(centralSurfaces)
- .setInteracting(
- StatusBarManager.WINDOW_STATUS_BAR,
- true,
- )
+ verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
},
)
@@ -1881,9 +1864,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val transitionStateFlow =
- prepareState(
- authenticationMethod = AuthenticationMethodModel.None,
- )
+ prepareState(authenticationMethod = AuthenticationMethodModel.None)
underTest.start()
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
// Swipe to Gone, more than halfway
@@ -1949,9 +1930,7 @@
fun switchToGone_whenKeyguardBecomesDisabled_whenOnShadeScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- prepareState(
- initialSceneKey = Scenes.Shade,
- )
+ prepareState(initialSceneKey = Scenes.Shade)
assertThat(currentScene).isEqualTo(Scenes.Shade)
underTest.start()
@@ -1981,10 +1960,7 @@
fun doesNotSwitchToGone_whenKeyguardBecomesDisabled_whenDeviceEntered() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- prepareState(
- isDeviceUnlocked = true,
- initialSceneKey = Scenes.Gone,
- )
+ prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Gone)
assertThat(currentScene).isEqualTo(Scenes.Gone)
assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isTrue()
underTest.start()
@@ -2097,10 +2073,7 @@
fun refreshLockscreenEnabled() =
testScope.runTest {
val transitionState =
- prepareState(
- isDeviceUnlocked = true,
- initialSceneKey = Scenes.Gone,
- )
+ prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Gone)
underTest.start()
val isLockscreenEnabled by
collectLastValue(kosmos.deviceEntryInteractor.isLockscreenEnabled)
@@ -2174,10 +2147,7 @@
runCurrent()
verifyDuringTransition?.invoke()
- transitionStateFlow.value =
- ObservableTransitionState.Idle(
- currentScene = toScene,
- )
+ transitionStateFlow.value = ObservableTransitionState.Idle(currentScene = toScene)
runCurrent()
verifyAfterTransition?.invoke()
}
@@ -2262,7 +2232,7 @@
private fun TestScope.allowHapticsOnSfps(
isPowerButtonDown: Boolean = false,
- lastPowerPress: Long = 10000
+ lastPowerPress: Long = 10000,
) {
kosmos.fakeKeyEventRepository.setPowerButtonDown(isPowerButtonDown)
@@ -2287,7 +2257,7 @@
private fun TestScope.setupBiometricAuth(
hasSfps: Boolean = false,
hasUdfps: Boolean = false,
- hasFace: Boolean = false
+ hasFace: Boolean = false,
) {
if (hasSfps) {
setFingerprintSensorType(FingerprintSensorType.POWER_BUTTON)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
index 851b7b9..ba559b5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
@@ -21,6 +21,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ShowOrHideOverlay
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -32,6 +34,7 @@
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -125,6 +128,63 @@
@Test
@EnableSceneContainer
+ fun legacyPanelExpansion_dualShade_whenIdle_whenLocked() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+ changeScene(Scenes.Lockscreen) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ changeScene(Scenes.Bouncer) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ showOverlay(Overlays.NotificationsShade) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ showOverlay(Overlays.QuickSettingsShade) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun legacyPanelExpansion_dualShade_whenIdle_whenUnlocked() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ val unlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+
+ assertThat(unlockStatus)
+ .isEqualTo(DeviceUnlockStatus(true, DeviceUnlockSource.Fingerprint))
+
+ val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+ changeScene(Scenes.Gone) { assertThat(panelExpansion).isEqualTo(0f) }
+ assertThat(panelExpansion).isEqualTo(0f)
+
+ showOverlay(Overlays.NotificationsShade) { progress ->
+ assertThat(panelExpansion).isEqualTo(progress)
+ }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ showOverlay(Overlays.QuickSettingsShade) {
+ // Notification shade is already expanded, so moving to QS shade should also be 1f.
+ assertThat(panelExpansion).isEqualTo(1f)
+ }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+ }
+
+ @Test
+ @EnableSceneContainer
fun shouldHideStatusBarIconsWhenExpanded_goneScene() =
testScope.runTest {
underTest = kosmos.panelExpansionInteractorImpl
@@ -193,4 +253,72 @@
assertThat(currentScene).isEqualTo(toScene)
}
+
+ private fun TestScope.showOverlay(
+ toOverlay: OverlayKey,
+ assertDuringProgress: ((progress: Float) -> Unit) = {},
+ ) {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val progressFlow = MutableStateFlow(0f)
+ transitionState.value =
+ if (checkNotNull(currentOverlays).isEmpty()) {
+ ShowOrHideOverlay(
+ overlay = toOverlay,
+ fromContent = checkNotNull(currentScene),
+ toContent = toOverlay,
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = flowOf(emptySet()),
+ progress = progressFlow,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ } else {
+ ObservableTransitionState.Transition.ReplaceOverlay(
+ fromOverlay = checkNotNull(currentOverlays).first(),
+ toOverlay = toOverlay,
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = flowOf(emptySet()),
+ progress = progressFlow,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ }
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.2f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.6f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 1f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ transitionState.value =
+ ObservableTransitionState.Idle(
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = setOf(toOverlay),
+ )
+ if (checkNotNull(currentOverlays).isEmpty()) {
+ fakeSceneDataSource.showOverlay(toOverlay)
+ } else {
+ fakeSceneDataSource.replaceOverlay(
+ from = checkNotNull(currentOverlays).first(),
+ to = toOverlay,
+ )
+ }
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ assertThat(currentOverlays).containsExactly(toOverlay)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt
index 2a2817b..ad2b23e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt
@@ -88,6 +88,26 @@
}
@Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun isDualShade_flagEnabled_true() =
+ testScope.runTest {
+ // Initiate collection.
+ val shadeMode by collectLastValue(underTest.shadeMode)
+
+ assertThat(underTest.isDualShade).isTrue()
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun isDualShade_flagDisabled_false() =
+ testScope.runTest {
+ // Initiate collection.
+ val shadeMode by collectLastValue(underTest.shadeMode)
+
+ assertThat(underTest.isDualShade).isFalse()
+ }
+
+ @Test
fun getTopEdgeSplitFraction_narrowScreen_splitInHalf() =
testScope.runTest {
// Ensure isShadeLayoutWide is collected.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
index 469a7bc..3053672 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -38,7 +38,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.DelayableExecutor
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index 6c8db91..84f7a51 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -28,4 +28,8 @@
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">100dp</dimen>
<dimen name="widget_label_font_size">18sp</dimen>
+
+ <!-- New keyboard shortcut helper -->
+ <dimen name="shortcut_helper_width">704dp</dimen>
+ <dimen name="shortcut_helper_height">1208dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/drawable/ic_volume_media_off.xml b/packages/SystemUI/res/drawable/ic_volume_media_off.xml
deleted file mode 100644
index 875b7b6..0000000
--- a/packages/SystemUI/res/drawable/ic_volume_media_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 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
- -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_volume_media_mute" />
-</selector>
diff --git a/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml b/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
index 06d1bf4..a15532f 100644
--- a/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
+++ b/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
@@ -2,14 +2,15 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/shortcut_helper_sheet_container"
+ android:layout_gravity="center_horizontal|bottom"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/shortcut_helper_sheet"
style="@style/ShortcutHelperBottomSheet"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/shortcut_helper_width"
+ android:layout_height="@dimen/shortcut_helper_height"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
diff --git a/packages/SystemUI/res/layout/ambient_status_bar_view.xml b/packages/SystemUI/res/layout/ambient_status_bar_view.xml
index 7d765ce..825824a 100644
--- a/packages/SystemUI/res/layout/ambient_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/ambient_status_bar_view.xml
@@ -53,6 +53,15 @@
app:layout_constraintEnd_toEndOf="parent">
<com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_location_active"
+ android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
+ android:src="@drawable/ic_location"
+ android:visibility="gone"
+ android:contentDescription="@string/location_active_dream_overlay_content_description" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/dream_overlay_alarm_set"
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/raw/trackpad_recent_apps_edu.json b/packages/SystemUI/res/raw/trackpad_recent_apps_edu.json
new file mode 100644
index 0000000..c2e945d
--- /dev/null
+++ b/packages/SystemUI/res/raw/trackpad_recent_apps_edu.json
@@ -0,0 +1 @@
+{"v":"5.12.1","fr":60,"ip":0,"op":511,"w":554,"h":564,"nm":"Trackpad-JSON_Recents-EDU","ddd":0,"assets":[{"id":"comp_0","nm":"Recents_EDU Loop","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"CNTL || playback","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"s":true,"x":{"a":0,"k":0},"y":{"a":0,"k":0}},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Picker","np":3,"mn":"Pseudo/@@WcSiov6sT3a4/s0XPKYEOQ","ix":1,"en":1,"ef":[{"ty":7,"nm":"Menu","mn":"Pseudo/@@WcSiov6sT3a4/s0XPKYEOQ-0001","ix":1,"v":{"a":0,"k":2}}]},{"ty":5,"nm":"OUTPUT","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"k":[{"s":[0],"t":142,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.001],"t":143,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.002],"t":144,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.003],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.004],"t":146,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.006],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.008],"t":148,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.01],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.012],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.016],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.02],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.025],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.031],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.038],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.047],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.059],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.073],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.091],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.116],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.15],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.196],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.249],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.306],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.366],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.425],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.481],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.53],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.575],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.614],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.648],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.678],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.706],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.73],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.752],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.772],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.79],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.807],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.822],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.836],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.849],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.861],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.873],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.883],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.892],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.901],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.91],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.917],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.925],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.931],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.937],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.943],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.949],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.954],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.958],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.963],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.967],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.97],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.974],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.977],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.98],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.983],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.985],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.987],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.989],"t":205,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.991],"t":206,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.993],"t":207,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.994],"t":208,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.996],"t":209,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.997],"t":210,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.998],"t":211,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.998],"t":212,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.999],"t":213,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1],"t":215,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1],"t":250,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.009],"t":251,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.038],"t":252,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.093],"t":253,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.193],"t":254,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.4],"t":255,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.636],"t":256,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.739],"t":257,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.8],"t":258,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.84],"t":259,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.871],"t":260,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.894],"t":261,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.912],"t":262,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.928],"t":263,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.94],"t":264,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.951],"t":265,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.959],"t":266,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.967],"t":267,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.973],"t":268,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.979],"t":269,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.983],"t":270,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.987],"t":271,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.99],"t":272,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.993],"t":273,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.995],"t":274,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.997],"t":275,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.998],"t":276,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.999],"t":278,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2],"t":380,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.009],"t":381,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.038],"t":382,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.093],"t":383,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.193],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.4],"t":385,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.636],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.739],"t":387,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.8],"t":388,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.84],"t":389,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.871],"t":390,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.894],"t":391,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.912],"t":392,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.928],"t":393,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.94],"t":394,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.951],"t":395,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.959],"t":396,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.967],"t":397,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.973],"t":398,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.979],"t":399,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.983],"t":400,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.987],"t":401,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.99],"t":402,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.993],"t":403,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.995],"t":404,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.997],"t":405,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.999],"t":408,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]}}]},{"ty":5,"nm":"Keys","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.831],"y":[0.109]},"o":{"x":[0.458],"y":[0.053]},"t":142,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0.43]},"t":161,"s":[0.15]},{"t":217,"s":[1],"h":1},{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":250,"s":[1]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":255,"s":[1.4]},{"t":280,"s":[2],"h":1},{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":380,"s":[2]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":385,"s":[2.4]},{"t":410,"s":[3]}]}}]},{"ty":5,"nm":"State (holds)","np":3,"mn":"ADBE Slider Control","ix":4,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":0}}]}],"shapes":[],"ip":0,"op":451,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null :: Taskbar drop","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"k":[{"s":[252,278,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,278.45,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,279.615,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,281.252,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,283.166,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,287.233,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,289.181,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,290.982,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,292.599,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,294.012,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,295.216,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,296.216,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,297.023,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,297.655,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.131,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.474,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.705,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.465,0],"t":212,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.226,0],"t":215,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298,0],"t":377,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.382,0],"t":378,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,299.372,0],"t":379,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,300.764,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,302.391,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,305.848,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,307.504,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,309.035,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,310.409,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,311.611,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,312.634,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,313.483,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,314.169,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,314.706,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.112,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.403,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.717,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.474,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.192,0],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Taskbar Lofi","parent":3,"refId":"comp_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":134,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":143,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":432,"s":[100]},{"t":444,"s":[0]}]},"r":{"a":0,"k":0},"p":{"s":true,"x":{"a":0,"k":0},"y":{"k":[{"s":[26.984],"t":127,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.971],"t":128,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.95],"t":129,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.921],"t":130,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.882],"t":131,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.83],"t":132,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.765],"t":133,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.685],"t":134,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.589],"t":135,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.478],"t":136,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.349],"t":137,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.205],"t":138,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.072],"t":139,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.926],"t":140,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.764],"t":141,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.589],"t":142,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.397],"t":143,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.187],"t":144,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.959],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.711],"t":146,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.44],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.146],"t":148,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.826],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.479],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.1],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.686],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.236],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[21.745],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[21.207],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[20.616],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.967],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.248],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.457],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.578],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.602],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.514],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.303],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[12.954],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[11.477],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[9.885],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[8.215],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[6.526],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[4.878],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[3.338],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.928],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.659],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.475],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-1.485],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-2.388],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-3.192],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-3.911],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-4.556],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-5.136],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-5.662],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.135],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.563],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.951],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-7.303],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-7.622],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-7.913],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.175],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.413],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.628],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.823],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.998],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.155],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.296],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.42],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.531],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.627],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.711],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.783],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.843],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.893],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.933],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.963],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.984],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.996],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]}},"a":{"a":0,"k":[91,15,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":138,"s":[17.5]},{"t":205,"s":[100]}]}}]}],"w":182,"h":30,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":3,"nm":"Focus Task :: Lift & Drop","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"s":true,"x":{"a":0,"k":252},"y":{"k":[{"s":[157.385],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.28],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.128],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.026],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.901],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.75],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.564],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.335],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.054],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.706],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.275],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[154.73],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[154.03],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[153.103],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[151.8],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[150.035],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[148.047],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.867],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[143.589],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[141.341],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[139.241],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[137.346],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[135.666],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[134.185],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[132.878],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[131.718],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[130.684],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[129.755],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[128.916],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[128.155],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[127.462],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[126.829],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[126.249],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[125.715],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[125.221],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[124.765],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[124.343],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[123.951],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[123.587],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[123.249],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.934],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.641],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.369],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.114],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.877],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.657],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.452],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.26],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.082],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.918],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.764],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.623],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.492],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.371],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.261],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.158],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.065],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.98],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.903],"t":205,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.835],"t":206,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.718],"t":208,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.629],"t":210,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.51],"t":215,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.5],"t":250,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.746],"t":251,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.54],"t":252,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.071],"t":253,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[124.808],"t":254,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[130.5],"t":255,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[136.982],"t":256,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[139.835],"t":257,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[141.489],"t":258,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[142.613],"t":259,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[143.442],"t":260,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[144.082],"t":261,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[144.593],"t":262,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.01],"t":263,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.354],"t":264,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.642],"t":265,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.884],"t":266,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.089],"t":267,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.262],"t":268,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.409],"t":269,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.534],"t":270,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.638],"t":271,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.725],"t":272,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.857],"t":274,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147],"t":380,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147.094],"t":381,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147.397],"t":382,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147.982],"t":383,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[149.027],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[151.2],"t":385,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[153.675],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[154.764],"t":387,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.396],"t":388,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.825],"t":389,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.141],"t":390,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.386],"t":391,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.581],"t":392,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.74],"t":393,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.871],"t":394,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.981],"t":395,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.074],"t":396,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.218],"t":398,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.362],"t":401,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]}},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"matte","parent":5,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"k":[{"s":[503.613,314.758],"t":144,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.134,314.459],"t":146,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.832,314.27],"t":147,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.464,314.04],"t":148,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.025,313.765],"t":149,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[501.487,313.429],"t":150,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[500.824,313.015],"t":151,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[500.023,312.514],"t":152,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[499.032,311.895],"t":153,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[497.818,311.136],"t":154,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[496.328,310.205],"t":155,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[494.484,309.053],"t":156,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[492.194,307.621],"t":157,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[489.307,305.817],"t":158,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[485.592,303.495],"t":159,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[480.67,300.419],"t":160,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[473.76,296.1],"t":161,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[464.395,290.247],"t":162,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[453.849,283.656],"t":163,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[442.286,276.429],"t":164,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[430.198,268.874],"t":165,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[418.274,261.421],"t":166,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[407.131,254.457],"t":167,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[397.077,248.173],"t":168,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[388.165,242.603],"t":169,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[380.31,237.694],"t":170,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[373.373,233.358],"t":171,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[367.218,229.511],"t":172,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[361.732,226.082],"t":173,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[356.803,223.002],"t":174,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[352.354,220.221],"t":175,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[348.318,217.699],"t":176,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[344.643,215.402],"t":177,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[341.283,213.302],"t":178,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[338.205,211.378],"t":179,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[335.37,209.606],"t":180,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[332.752,207.97],"t":181,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[330.33,206.456],"t":182,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[328.092,205.058],"t":183,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[326.012,203.757],"t":184,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[324.082,202.552],"t":185,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[322.291,201.432],"t":186,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[320.617,200.386],"t":187,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[319.062,199.414],"t":188,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[317.618,198.512],"t":189,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[316.267,197.667],"t":190,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[315.013,196.883],"t":191,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[313.845,196.153],"t":192,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[312.756,195.472],"t":193,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[311.738,194.837],"t":194,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[310.793,194.246],"t":195,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[309.921,193.7],"t":196,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[309.107,193.192],"t":197,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[308.359,192.724],"t":198,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[307.663,192.289],"t":199,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[307.02,191.888],"t":200,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[306.436,191.522],"t":201,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[305.891,191.182],"t":202,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[305.399,190.874],"t":203,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[304.946,190.591],"t":204,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[304.539,190.337],"t":205,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[304.178,190.112],"t":206,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.85,189.906],"t":207,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.555,189.722],"t":208,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.306,189.566],"t":209,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.082,189.427],"t":210,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.892,189.308],"t":211,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.617,189.135],"t":213,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.4,189],"t":250,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.247,188.904],"t":251,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[301.752,188.595],"t":252,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[300.798,187.999],"t":253,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[299.093,186.933],"t":254,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[295.546,184.716],"t":255,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[291.506,182.192],"t":256,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[289.729,181.08],"t":257,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[288.698,180.436],"t":258,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.998,179.999],"t":259,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.481,179.676],"t":260,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.082,179.427],"t":261,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.764,179.227],"t":262,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.504,179.065],"t":263,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.29,178.931],"t":264,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.11,178.819],"t":265,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.832,178.645],"t":267,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.555,178.472],"t":270,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.272,178.295],"t":278,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.264,178.29],"t":380,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.222,179.514],"t":381,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[293.538,183.461],"t":382,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[305.714,191.071],"t":383,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[327.48,204.675],"t":384,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[372.758,232.974],"t":385,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[424.317,265.198],"t":386,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[447.009,279.381],"t":387,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[460.167,287.605],"t":388,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[469.103,293.19],"t":389,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[475.697,297.31],"t":390,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[480.788,300.492],"t":391,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[484.853,303.033],"t":392,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[488.172,305.107],"t":393,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[490.906,306.816],"t":394,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[493.198,308.249],"t":395,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[495.121,309.451],"t":396,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[496.752,310.47],"t":397,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[498.133,311.333],"t":398,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[499.301,312.063],"t":399,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[500.29,312.681],"t":400,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[501.123,313.202],"t":401,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[501.814,313.634],"t":402,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.391,313.994],"t":403,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.861,314.288],"t":404,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.238,314.524],"t":405,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.53,314.706],"t":406,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0]},"r":{"k":[{"s":[27.974],"t":144,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.959],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.942],"t":146,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.922],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.898],"t":148,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.869],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.833],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.789],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.736],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.67],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.589],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.49],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.368],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.216],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.024],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.777],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.45],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.991],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.37],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.669],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.901],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.098],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.306],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[21.566],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[20.898],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[20.306],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.785],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.324],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.915],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.551],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.223],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.928],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.66],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.416],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.193],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.988],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.8],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.626],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.465],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.316],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.178],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.05],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.931],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.82],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.717],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.621],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.531],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.448],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.37],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.298],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.23],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.167],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.11],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.055],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.006],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.96],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.917],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.878],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.842],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.809],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.779],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.752],"t":205,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.728],"t":206,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.706],"t":207,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.687],"t":208,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.67],"t":209,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.655],"t":210,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.643],"t":211,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.633],"t":212,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.624],"t":213,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.61],"t":250,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.603],"t":251,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.579],"t":252,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.532],"t":253,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.45],"t":254,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.278],"t":255,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.082],"t":256,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.996],"t":257,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.946],"t":258,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.912],"t":259,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.887],"t":260,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.868],"t":261,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.853],"t":262,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.84],"t":263,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.83],"t":264,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.821],"t":265,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.808],"t":267,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.794],"t":270,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.78],"t":278,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.78],"t":380,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.907],"t":381,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.318],"t":382,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.109],"t":383,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.524],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.468],"t":385,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.82],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.295],"t":387,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.15],"t":388,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.731],"t":389,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.16],"t":390,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.491],"t":391,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.755],"t":392,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.971],"t":393,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.149],"t":394,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.298],"t":395,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.423],"t":396,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.529],"t":397,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.619],"t":398,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.694],"t":399,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.759],"t":400,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.813],"t":401,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.858],"t":402,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.895],"t":403,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.926],"t":404,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.95],"t":405,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.969],"t":406,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.993],"t":408,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Recents_LofiApp","parent":6,"tt":1,"tp":6,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[252,157.5,0]},"s":{"k":[{"s":[99.923,99.923,100],"t":144,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.828,99.828,100],"t":146,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.768,99.768,100],"t":147,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.695,99.695,100],"t":148,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.608,99.608,100],"t":149,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.501,99.501,100],"t":150,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.37,99.37,100],"t":151,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.211,99.211,100],"t":152,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.014,99.014,100],"t":153,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.773,98.773,100],"t":154,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.478,98.478,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.112,98.112,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.658,97.658,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.085,97.085,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.348,96.348,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.371,95.371,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94,94,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.142,92.142,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.049,90.049,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[87.755,87.755,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.357,85.357,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[82.991,82.991,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.78,80.78,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[78.785,78.785,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[77.017,77.017,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[75.458,75.458,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[74.082,74.082,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[72.861,72.861,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[71.772,71.772,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70.794,70.794,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[69.911,69.911,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[69.111,69.111,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.382,68.382,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[67.715,67.715,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[67.104,67.104,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[66.542,66.542,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[66.022,66.022,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[65.542,65.542,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[65.098,65.098,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[64.685,64.685,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[64.302,64.302,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.947,63.947,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.615,63.615,100],"t":187,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.306,63.306,100],"t":188,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.02,63.02,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.751,62.751,100],"t":190,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.503,62.503,100],"t":191,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.271,62.271,100],"t":192,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.055,62.055,100],"t":193,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.853,61.853,100],"t":194,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.665,61.665,100],"t":195,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.492,61.492,100],"t":196,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.331,61.331,100],"t":197,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.182,61.182,100],"t":198,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.044,61.044,100],"t":199,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.917,60.917,100],"t":200,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.801,60.801,100],"t":201,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.693,60.693,100],"t":202,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.595,60.595,100],"t":203,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.505,60.505,100],"t":204,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.424,60.424,100],"t":205,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.353,60.353,100],"t":206,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.288,60.288,100],"t":207,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.229,60.229,100],"t":208,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.18,60.18,100],"t":209,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.135,60.135,100],"t":210,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.098,60.098,100],"t":211,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.043,60.043,100],"t":213,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60,60,100],"t":250,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.97,59.97,100],"t":251,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.871,59.871,100],"t":252,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.682,59.682,100],"t":253,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.344,59.344,100],"t":254,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[58.64,58.64,100],"t":255,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.839,57.839,100],"t":256,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.486,57.486,100],"t":257,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.281,57.281,100],"t":258,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.142,57.142,100],"t":259,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.04,57.04,100],"t":260,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.961,56.961,100],"t":261,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.898,56.898,100],"t":262,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.846,56.846,100],"t":263,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.804,56.804,100],"t":264,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.768,56.768,100],"t":265,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.713,56.713,100],"t":267,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.658,56.658,100],"t":270,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.602,56.602,100],"t":278,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.6,56.6,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.989,56.989,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[58.242,58.242,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.657,60.657,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[64.976,64.976,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[73.96,73.96,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[84.19,84.19,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.692,88.692,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[91.303,91.303,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.076,93.076,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.384,94.384,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.394,95.394,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.201,96.201,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.859,96.859,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.402,97.402,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.857,97.857,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.238,98.238,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.562,98.562,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.836,98.836,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.068,99.068,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.264,99.264,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.429,99.429,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.566,99.566,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.681,99.681,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.774,99.774,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.849,99.849,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.907,99.907,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"w":504,"h":315,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":7,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[0]},{"t":277,"s":[100]}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,-30.035,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[176.678,176.678,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"second Tasks Zoom back","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,0.15,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":380,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.05,0.05,0.05],"y":[0.7,0.7,0]},"t":385,"s":[98,98,100]},{"t":410,"s":[95,95,100]}]}},"ao":0,"shapes":[],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Null :: Reposition Side Task","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.8,"y":0.15},"o":{"x":0.3,"y":0},"t":250,"s":[-318.4,-38,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.05,"y":0.7},"t":255,"s":[-277.34,-48.1,0],"to":[0,0,0],"ti":[0,0,0]},{"t":280,"s":[-215.75,-63.25,0]}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":277,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[0,-111.72,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-111.197,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-109.514,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-106.268,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-100.462,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-88.39,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-74.643,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-68.591,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-65.083,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-62.7,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-60.943,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-59.584,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-58.5,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-57.616,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-56.886,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-56.276,0],"t":265,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-55.762,0],"t":266,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-55.328,0],"t":267,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.96,0],"t":268,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.648,0],"t":269,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.385,0],"t":270,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.163,0],"t":271,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.977,0],"t":272,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.824,0],"t":273,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.698,0],"t":274,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.598,0],"t":275,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.521,0],"t":276,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.463,0],"t":277,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.424,0],"t":278,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":10,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.05,"y":0.963},"t":217,"s":[-84.8,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":250,"s":[0,0,0]}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.8,0.8],"y":[0.15,0.15]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":250,"s":[302.4,189]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0.7]},"t":255,"s":[227.56,142.34]},{"t":280,"s":[115.3,72.35]}]},"p":{"a":0,"k":[0,0]},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":250,"s":[14.6]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":255,"s":[14.272]},{"t":280,"s":[13.78]}]},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":14,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":277,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[0,-53.175,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.175,0],"t":510,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":9,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.8,"y":0.15},"o":{"x":0.3,"y":0},"t":250,"s":[-411.95,20.325,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.05,"y":0.7},"t":255,"s":[-333.47,29.183,0],"to":[0,0,0],"ti":[0,0,0]},{"t":280,"s":[-215.75,42.47,0]}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[115.3,72.35]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":13.78},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Taskbar Lofi","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"app - 5","parent":9,"sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[51.5,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.652,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.136,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.013,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.449,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.806,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.3,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[66.437,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[68.94,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[70.432,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[71.462,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[72.229,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[72.83,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[73.314,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[73.714,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.048,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.334,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.578,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.789,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.971,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.131,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.269,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.389,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.493,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.584,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.663,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.731,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.789,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.839,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.915,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.982,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[76,0,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.779,0,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.066,0,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[73.709,0,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[71.271,0,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[66.2,0,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[60.425,0,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.886,0,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.41,0,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.409,0,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.67,0,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.1,0,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.646,0,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.275,0,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.968,0,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.711,0,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.495,0,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.312,0,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.157,0,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.026,0,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.916,0,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.822,0,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.745,0,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.68,0,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.628,0,0],"t":404,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.585,0,0],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.552,0,0],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.501,0,0],"t":409,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[167,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7511","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[167,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 5","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"app - 4","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[123.341,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.654,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.223,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[125.146,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[126.662,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[129.549,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[132.838,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[134.455,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[135.421,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[136.083,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[136.576,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[136.962,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.272,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.528,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.742,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.924,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.08,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.216,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.334,15,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.437,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.527,15,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.606,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.734,15,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.869,15,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.864,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.402,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.527,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[135.96,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[132.701,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[129.002,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[127.358,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[126.406,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[125.763,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[125.288,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.923,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.633,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.396,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.199,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.034,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.895,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.776,15,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.675,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.589,15,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.516,15,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.403,15,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.299,15,0],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[139,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7508","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[139,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 4","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"app - 3","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[104.041,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.182,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.436,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.844,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.517,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[106.808,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[108.265,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[108.981,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.409,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.703,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.923,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.092,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.228,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.341,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.436,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.517,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.587,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.648,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.746,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.853,15,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.956,15,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.938,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.73,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.34,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.649,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[108.197,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[106.559,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.828,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.403,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.117,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.906,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.745,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.616,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.511,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.424,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.35,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.288,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.19,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.091,15,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[111,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7507","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[111,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 3","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"app - 2","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[84.704,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.639,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.537,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.371,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.048,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.684,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.505,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.398,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.324,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.271,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.195,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.123,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.045,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.068,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.166,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.338,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.702,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.112,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.294,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.399,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.47,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.521,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.593,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.676,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[83,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7506","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[83,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 2","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"app - 1","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[65.439,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.229,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.849,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.236,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.226,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.296,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.111,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[58.033,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.388,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.945,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.616,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.359,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.154,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.984,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.842,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.72,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.616,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.525,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.447,15,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.378,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.317,15,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.265,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.219,15,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.178,15,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.143,15,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.113,15,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.066,15,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.012,15,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55,15,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.092,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.403,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.986,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.027,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.212,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.67,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[62.762,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.396,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.825,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.141,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.385,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.578,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.736,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.867,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.977,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.07,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.149,15,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.217,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.274,15,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.323,15,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.364,15,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.426,15,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.491,15,0],"t":407,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[55,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7505","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[55,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 1","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"divider","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":90},"p":{"k":[{"s":[51,15,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.913,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.615,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.073,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.194,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.751,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.001,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.869,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[40.328,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.409,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.778,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.309,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.941,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.645,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.402,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.199,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.025,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.876,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.747,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.635,15,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.536,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.451,15,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.376,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.31,15,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.253,15,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.203,15,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.161,15,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.124,15,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.093,15,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.068,15,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.047,15,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.017,15,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36,15,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.129,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.569,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.403,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.895,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.999,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.522,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.088,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.994,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[48.607,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.059,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.407,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.683,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.909,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.096,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.253,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.386,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.499,15,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.596,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.677,15,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.747,15,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.806,15,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.854,15,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.895,15,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.927,15,0],"t":404,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.973,15,0],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2,-0.5],[2,-0.5]],"c":false}],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.019,-0.5],[2.019,-0.5]],"c":false}],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.077,-0.5],[2.077,-0.5]],"c":false}],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.185,-0.5],[2.185,-0.5]],"c":false}],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.361,-0.5],[2.361,-0.5]],"c":false}],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.65,-0.5],[2.65,-0.5]],"c":false}],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.2,-0.5],[3.2,-0.5]],"c":false}],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.829,-0.5],[3.829,-0.5]],"c":false}],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.136,-0.5],[4.136,-0.5]],"c":false}],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.318,-0.5],[4.318,-0.5]],"c":false}],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.444,-0.5],[4.444,-0.5]],"c":false}],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.538,-0.5],[4.538,-0.5]],"c":false}],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.612,-0.5],[4.612,-0.5]],"c":false}],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.671,-0.5],[4.671,-0.5]],"c":false}],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.72,-0.5],[4.72,-0.5]],"c":false}],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.761,-0.5],[4.761,-0.5]],"c":false}],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.796,-0.5],[4.796,-0.5]],"c":false}],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.826,-0.5],[4.826,-0.5]],"c":false}],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.852,-0.5],[4.852,-0.5]],"c":false}],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.874,-0.5],[4.874,-0.5]],"c":false}],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.894,-0.5],[4.894,-0.5]],"c":false}],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.91,-0.5],[4.91,-0.5]],"c":false}],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.925,-0.5],[4.925,-0.5]],"c":false}],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.938,-0.5],[4.938,-0.5]],"c":false}],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.949,-0.5],[4.949,-0.5]],"c":false}],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.959,-0.5],[4.959,-0.5]],"c":false}],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.967,-0.5],[4.967,-0.5]],"c":false}],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.974,-0.5],[4.974,-0.5]],"c":false}],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.98,-0.5],[4.98,-0.5]],"c":false}],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.99,-0.5],[4.99,-0.5]],"c":false}],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.996,-0.5],[4.996,-0.5]],"c":false}],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,-0.5],[5,-0.5]],"c":false}],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.973,-0.5],[4.973,-0.5]],"c":false}],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.887,-0.5],[4.887,-0.5]],"c":false}],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.72,-0.5],[4.72,-0.5]],"c":false}],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.421,-0.5],[4.421,-0.5]],"c":false}],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.8,-0.5],[3.8,-0.5]],"c":false}],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.093,-0.5],[3.093,-0.5]],"c":false}],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.782,-0.5],[2.782,-0.5]],"c":false}],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.601,-0.5],[2.601,-0.5]],"c":false}],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.479,-0.5],[2.479,-0.5]],"c":false}],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.388,-0.5],[2.388,-0.5]],"c":false}],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.318,-0.5],[2.318,-0.5]],"c":false}],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.263,-0.5],[2.263,-0.5]],"c":false}],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.217,-0.5],[2.217,-0.5]],"c":false}],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.18,-0.5],[2.18,-0.5]],"c":false}],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.148,-0.5],[2.148,-0.5]],"c":false}],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.122,-0.5],[2.122,-0.5]],"c":false}],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.099,-0.5],[2.099,-0.5]],"c":false}],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.081,-0.5],[2.081,-0.5]],"c":false}],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.064,-0.5],[2.064,-0.5]],"c":false}],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.051,-0.5],[2.051,-0.5]],"c":false}],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.039,-0.5],[2.039,-0.5]],"c":false}],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.03,-0.5],[2.03,-0.5]],"c":false}],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.022,-0.5],[2.022,-0.5]],"c":false}],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.01,-0.5],[2.01,-0.5]],"c":false}],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.006,-0.5],[2.006,-0.5]],"c":false}],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.004,-0.5],[2.004,-0.5]],"c":false}],"t":407,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.001,-0.5],[2.001,-0.5]],"c":false}],"t":408,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"divider","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":9,"sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[-52.349,0.652,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.453,0.652,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.813,0.652,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.464,0.652,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.515,0.652,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.247,0.652,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-59.565,0.652,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-63.323,0.652,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-65.162,0.652,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-66.258,0.652,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-67.015,0.652,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-67.578,0.652,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.019,0.652,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.375,0.652,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.668,0.652,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.914,0.652,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.122,0.652,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.301,0.652,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.456,0.652,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.59,0.652,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.708,0.652,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.81,0.652,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.9,0.652,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.978,0.652,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.047,0.652,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.106,0.652,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.157,0.652,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.2,0.652,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.268,0.652,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.328,0.652,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.349,0.652,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.193,0.652,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.662,0.652,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.662,0.652,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-66.874,0.652,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-63.132,0.652,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.906,0.652,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.04,0.652,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.956,0.652,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.22,0.652,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.678,0.652,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.259,0.652,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.925,0.652,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.654,0.652,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.43,0.652,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.241,0.652,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.082,0.652,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.947,0.652,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.831,0.652,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.734,0.652,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.65,0.652,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.58,0.652,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.522,0.652,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.474,0.652,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.435,0.652,0],"t":404,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.404,0.652,0],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.354,0.652,0],"t":408,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[6.826,6.826,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 12","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[2.5,9.501]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 12","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 11","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[2.5,2.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 11","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 5","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[9.5,2.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 5","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true}},"nm":"Path 1","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 1","hd":false},{"ind":2,"ty":"sh","ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true}},"nm":"Path 2","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 2","hd":false},{"ty":"st","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.4},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"icon","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[10.326,10.326]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"icon","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[91,15,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[{"s":[120,4],"t":155,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.383,4.161],"t":156,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.592,4.668],"t":157,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[123.818,5.601],"t":158,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[127.463,7.13],"t":159,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[133.427,9.631],"t":160,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[144.8,14.4],"t":161,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[157.801,19.852],"t":162,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[164.141,22.511],"t":163,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[167.915,24.093],"t":164,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[170.516,25.184],"t":165,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[172.458,25.999],"t":166,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[173.978,26.636],"t":167,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[175.203,27.15],"t":168,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[176.216,27.574],"t":169,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[177.065,27.931],"t":170,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[177.788,28.234],"t":171,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[178.406,28.493],"t":172,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[178.938,28.716],"t":173,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[179.399,28.909],"t":174,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[179.8,29.078],"t":175,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.149,29.224],"t":176,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.454,29.352],"t":177,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.718,29.463],"t":178,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.949,29.559],"t":179,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.148,29.643],"t":180,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.32,29.715],"t":181,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.467,29.777],"t":182,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.592,29.829],"t":183,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.697,29.873],"t":184,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.784,29.91],"t":185,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.855,29.939],"t":186,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.909,29.962],"t":187,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.978,29.991],"t":189,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[182,30],"t":380,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.445,29.767],"t":381,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[179.655,29.017],"t":382,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[176.204,27.569],"t":383,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[170.034,24.982],"t":384,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[157.2,19.6],"t":385,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[142.586,13.472],"t":386,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[136.154,10.774],"t":387,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[132.424,9.21],"t":388,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[129.891,8.148],"t":389,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[128.022,7.364],"t":390,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[126.579,6.759],"t":391,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[125.427,6.276],"t":392,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[124.487,5.881],"t":393,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[123.712,5.556],"t":394,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[123.062,5.284],"t":395,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[122.517,5.055],"t":396,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[122.055,4.862],"t":397,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.663,4.697],"t":398,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.332,4.559],"t":399,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.051,4.441],"t":400,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.815,4.342],"t":401,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.62,4.26],"t":402,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.456,4.191],"t":403,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.323,4.135],"t":404,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.216,4.091],"t":405,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.133,4.056],"t":406,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.073,4.03],"t":407,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.03,4.013],"t":408,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.008,4.003],"t":409,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":32.672},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Taskbar Lofi","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"Recents_LofiApp","fr":60,"pfr":1,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[339.937,151.75,0]},"a":{"a":0,"k":[339.937,151.75,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.021,-1.766],[0,0],[-2.043,0],[0,0],[1.022,1.767]],"o":[[-1.021,-1.766],[0,0],[-1.022,1.767],[0,0],[2.043,0],[0,0]],"v":[[2.297,-7.675],[-2.297,-7.675],[-9.64,5.025],[-7.343,9],[7.343,9],[9.64,5.025]],"c":true}},"nm":"Path 1","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":9},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[481.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[457.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[292,25]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[334,279]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109,28]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[425.5,208.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[160,56]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[400,158.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126,40]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[251,78.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[334,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[340,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":16},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82,171.125,0]},"a":{"a":0,"k":[82,171.125,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,177.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 4","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,165.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,171.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 2","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82.5,140.5,0]},"a":{"a":0,"k":[82,140.938,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,22]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Search","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,31.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"header","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,257.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 6","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,245.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 5","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,251.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,64]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,171]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"block","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,96.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,84.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,90.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 1","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app only","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":250,"s":[100]},{"t":256,"s":[0]}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[0,29.984,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.965,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.936,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.894,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.84,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.77,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.682,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.574,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.445,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.294,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.121,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.925,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.746,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.548,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.33,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.092,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,27.832,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,27.548,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,27.239,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,26.903,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,26.536,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,26.14,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,25.709,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,25.241,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,24.73,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,24.171,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,23.563,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,22.898,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,22.171,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,21.373,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,20.496,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,19.524,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,18.451,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,17.263,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,15.943,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,14.475,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,12.841,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,11.018,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,9.023,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,6.87,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,4.614,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,2.333,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,0.106,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-1.975,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-3.877,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-5.591,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-7.125,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-8.492,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-9.714,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-10.799,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-11.771,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-12.643,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-13.428,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-14.138,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-14.777,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-15.355,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-15.879,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-16.354,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-16.784,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-17.177,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-17.532,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-17.854,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.146,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.409,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.645,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.858,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.048,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.217,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.366,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.496,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.61,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.707,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.788,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.856,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.911,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.954,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.984,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":138,"s":[17.5]},{"t":205,"s":[100]}]}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":248,"s":[28,28]},{"t":258,"s":[36,36]}]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[33,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":248,"s":[33,0],"to":[0,0],"ti":[0,0]},{"t":258,"s":[41,0]}]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"right circle","bm":0,"hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":248,"s":[28,28]},{"t":258,"s":[36,36]}]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[-41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[-33,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":248,"s":[-33,0],"to":[0,0],"ti":[0,0]},{"t":258,"s":[-41,0]}]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"left circle","bm":0,"hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":248,"s":[28,28]},{"t":258,"s":[36,36]}]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"size","bm":0,"hd":false}],"ip":37,"op":345,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,459,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":18},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Frame 1321317559","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Recents_EDU Loop","parent":4,"tt":1,"tp":4,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[252,157.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":504,"h":315,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":50},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"illustrations: action key","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.768627464771,0.627451002598,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"illustrations: action key","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"k":[{"s":[7],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[7],"t":511,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lj":1,"ml":{"a":0,"k":4},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"frame","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}],"markers":[{"tm":121,"cm":"start","dr":0},{"tm":142,"cm":"gesture","dr":75},{"tm":250,"cm":"release","dr":36},{"tm":356,"cm":"FLIP","dr":0},{"tm":392,"cm":"launch","dr":66}],"props":{}}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/trackpad_recent_apps_success.json b/packages/SystemUI/res/raw/trackpad_recent_apps_success.json
new file mode 100644
index 0000000..bec6f35
--- /dev/null
+++ b/packages/SystemUI/res/raw/trackpad_recent_apps_success.json
@@ -0,0 +1 @@
+{"v":"5.12.1","fr":60,"ip":0,"op":50,"w":554,"h":564,"nm":"Trackpad-JSON_Recents-Success","ddd":0,"assets":[{"id":"comp_0","nm":"TrackpadAK_Success_Checkmark","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Check Rotate","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.12],"y":[1]},"o":{"x":[0.44],"y":[0]},"t":2,"s":[-16]},{"t":20,"s":[6]}]},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[95.049,95.049,100]}},"ao":0,"ip":0,"op":228,"st":-72,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Bounce","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.12],"y":[1]},"o":{"x":[0.44],"y":[0]},"t":12,"s":[0]},{"t":36,"s":[-6]}]},"p":{"a":0,"k":[81,127,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.263,0.263,0.833],"y":[1.126,1.126,1]},"o":{"x":[0.05,0.05,0.05],"y":[0.958,0.958,0]},"t":1,"s":[80,80,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.45,0.45,0.167],"y":[0.325,0.325,0]},"t":20,"s":[105,105,100]},{"t":36,"s":[100,100,100]}]}},"ao":0,"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-0.289},"p":{"a":0,"k":[14.364,-33.591,0]},"a":{"a":0,"k":[-0.125,0,0]},"s":{"a":0,"k":[104.744,104.744,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.401,-0.007],[-10.033,11.235]],"o":[[5.954,7.288],[1.401,0.007],[0,0]],"v":[[-28.591,4.149],[-10.73,26.013],[31.482,-21.255]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":3,"s":[0]},{"i":{"x":[0.22],"y":[1]},"o":{"x":[0.001],"y":[0.149]},"t":10,"s":[29]},{"t":27,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":11},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":5,"op":44,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[95,95,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.275,0.275,0.21],"y":[1.102,1.102,1]},"o":{"x":[0.037,0.037,0.05],"y":[0.476,0.476,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.252,0.252,0.47],"y":[0.159,0.159,0]},"t":16,"s":[120,120,100]},{"t":28,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.32,0.32],"y":[0.11,0.11]},"t":16,"s":[148,148]},{"t":28,"s":[136,136]}]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":88},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Checkbox - Widget","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Recents_LofiApp","fr":60,"pfr":1,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[339.937,151.75,0]},"a":{"a":0,"k":[339.937,151.75,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.021,-1.766],[0,0],[-2.043,0],[0,0],[1.022,1.767]],"o":[[-1.021,-1.766],[0,0],[-1.022,1.767],[0,0],[2.043,0],[0,0]],"v":[[2.297,-7.675],[-2.297,-7.675],[-9.64,5.025],[-7.343,9],[7.343,9],[9.64,5.025]],"c":true}},"nm":"Path 1","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":9},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[481.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[457.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[292,25]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[334,279]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109,28]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[425.5,208.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[160,56]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[400,158.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126,40]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[251,78.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[334,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[340,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":16},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82,171.125,0]},"a":{"a":0,"k":[82,171.125,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,177.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 4","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,165.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,171.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 2","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82.5,140.5,0]},"a":{"a":0,"k":[82,140.938,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,22]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Search","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,31.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"header","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,257.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 6","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,245.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 5","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,251.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,64]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,171]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"block","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,96.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,84.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,90.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 1","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app only","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"TrackpadAK_Success_Checkmark","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,198.5,0]},"a":{"a":0,"k":[95,95,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":190,"h":190,"ip":6,"op":50,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":389,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Global Position","np":4,"mn":"Pseudo/88900","ix":1,"en":1,"ef":[{"ty":10,"nm":"Master Parent","mn":"Pseudo/88900-0001","ix":1,"v":{"a":0,"k":2}},{"ty":3,"nm":"Global Position","mn":"Pseudo/88900-0002","ix":2,"v":{"k":[{"s":[277,197.5],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5],"t":49,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,459,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":18},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Frame 1321317559","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Recents_LofiApp","tt":1,"tp":4,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[252,157.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":504,"h":315,"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Global Position","np":4,"mn":"Pseudo/88900","ix":1,"en":1,"ef":[{"ty":10,"nm":"Master Parent","mn":"Pseudo/88900-0001","ix":1,"v":{"a":0,"k":2}},{"ty":3,"nm":"Global Position","mn":"Pseudo/88900-0002","ix":2,"v":{"k":[{"s":[277,197.5],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5],"t":49,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":50},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.768627464771,0.627451002598,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"illustrations: action key","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"k":[{"s":[7],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[7],"t":49,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lj":1,"ml":{"a":0,"k":4},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"frame","bm":0,"hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 2a27b47..3efe7a5 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -26,6 +26,10 @@
<dimen name="keyguard_clock_top_margin">8dp</dimen>
<dimen name="keyguard_smartspace_top_offset">0dp</dimen>
+ <!-- New keyboard shortcut helper -->
+ <dimen name="shortcut_helper_width">864dp</dimen>
+ <dimen name="shortcut_helper_height">728dp</dimen>
+
<!-- QS-->
<dimen name="qs_panel_padding_top">16dp</dimen>
<dimen name="qs_panel_padding">24dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e1808fa..00846cb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1005,6 +1005,10 @@
<dimen name="ksh_app_item_minimum_height">64dp</dimen>
<dimen name="ksh_category_separator_margin">16dp</dimen>
+ <!-- New keyboard shortcut helper -->
+ <dimen name="shortcut_helper_width">412dp</dimen>
+ <dimen name="shortcut_helper_height">728dp</dimen>
+
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
@@ -1976,6 +1980,14 @@
<dimen name="backlight_indicator_step_small_radius">4dp</dimen>
<dimen name="backlight_indicator_step_large_radius">28dp</dimen>
+ <!-- Touchpad gestures tutorial-->
+ <!-- This value is in unit of dp/ms
+ TriggerSwipeUpTouchTracker (which is base for gesture tutorial implementation) uses value
+ of 0.5dp but from manual testing it's too high and doesn't really feel like it's forcing
+ slowing down. Also for tutorial it should be fine to lean to the side of being more strict
+ rather than not strict enough and not teaching user the proper gesture as a result.-->
+ <dimen name="touchpad_recent_apps_gesture_velocity_threshold">0.05dp</dimen>
+
<!-- Broadcast dialog -->
<dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
<dimen name="broadcast_dialog_title_text_size">24sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 589d9dd..f9c2aef 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3369,6 +3369,8 @@
<!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
<string name="drag_split_not_supported">This notification does not support dragging to split screen</string>
+ <!-- Content description for the location icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_location_active">Location active</string>
<!-- Content description for the Wi-Fi off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
<string name="dream_overlay_status_bar_wifi_off">Wi\u2011Fi unavailable</string>
<!-- Content description for the priority mode icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
@@ -3561,6 +3563,9 @@
<!-- Content description for Wi-Fi not available icon on dream [CHAR LIMIT=NONE]-->
<string name="wifi_unavailable_dream_overlay_content_description">Wi-Fi not available</string>
+ <!-- Content description for location in use icon on dream [CHAR LIMIT=NONE] -->
+ <string name="location_active_dream_overlay_content_description">Location active</string>
+
<!-- Content description for camera blocked icon on dream [CHAR LIMIT=NONE] -->
<string name="camera_blocked_dream_overlay_content_description">Camera blocked</string>
@@ -3724,8 +3729,8 @@
<string name="touchpad_tutorial_back_gesture_button">Back gesture</string>
<!-- Label for button opening tutorial for back gesture on touchpad [CHAR LIMIT=NONE] -->
<string name="touchpad_tutorial_home_gesture_button">Home gesture</string>
- <!-- Label for button opening tutorial on using Action key from keyboard [CHAR LIMIT=NONE] -->
- <string name="touchpad_tutorial_action_key_button">Action key</string>
+ <!-- Label for button opening tutorial for "view recent apps" gesture on touchpad [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_recent_apps_gesture_button">View recent apps</string>
<!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] -->
<string name="touchpad_tutorial_done_button">Done</string>
<!-- BACK GESTURE -->
@@ -3747,6 +3752,15 @@
<string name="touchpad_home_gesture_success_title">Nice!</string>
<!-- Text shown to the user after they complete home gesture tutorial [CHAR LIMIT=NONE] -->
<string name="touchpad_home_gesture_success_body">You completed the go home gesture.</string>
+ <!-- RECENT APPS GESTURE -->
+ <!-- Touchpad recent apps gesture action name in tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_recent_apps_gesture_action_title">View recent apps</string>
+ <!-- Touchpad recent apps gesture guidance in gestures tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_recent_apps_gesture_guidance">Swipe up and hold using three fingers on your touchpad.</string>
+ <!-- Screen title after recent apps gesture was done successfully [CHAR LIMIT=NONE] -->
+ <string name="touchpad_recent_apps_gesture_success_title">Great job!</string>
+ <!-- Text shown to the user after they complete recent apps gesture tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_recent_apps_gesture_success_body">You completed the view recent apps gesture.</string>
<!-- KEYBOARD TUTORIAL-->
<!-- Action key tutorial title [CHAR LIMIT=NONE] -->
@@ -3802,16 +3816,16 @@
<string name="all_apps_edu_notification_content">Press the action key at any time. Tap to learn more gestures.</string>
<!-- Title for Extra Dim dialog [CHAR LIMIT=NONE] -->
- <string name="accessibility_deprecate_extra_dim_dialog_title">Extra dim is now part of the brightness bar</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_title">Extra dim is now part of the brightness slider</string>
<!-- Content description for Extra Dim dialog. This helps users understand that we could make screen much dimmer by lowering the brightness through the brightness bar in a dark environment. [CHAR LIMIT=NONE] -->
<string name="accessibility_deprecate_extra_dim_dialog_description">
- You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment.
+ You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed.
</string>
<!-- Label for button removing Extra Dim shortcuts [CHAR LIMIT=NONE] -->
- <string name="accessibility_deprecate_extra_dim_dialog_button">Remove extra dim shortcut</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button">Remove extra dim shortcuts</string>
<!-- Toast message for notifying users to use regular brightness bar to lower the brightness. [CHAR LIMIT=NONE] -->
<string name="accessibility_deprecate_extra_dim_dialog_toast">
- Extra dim shortcut removed. To lower your brightness, use the regular brightness bar.</string>
+ Extra dim shortcuts removed</string>
<!-- Label for category in QS Edit mode list of tiles, for tiles that are related to connectivity, e.g. Internet. [CHAR LIMIT=NONE] -->
<string name="qs_edit_mode_category_connectivity">
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 0f1da50..8f55961 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -70,7 +70,6 @@
"jsr330",
"//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
"//frameworks/libs/systemui:msdl",
- "//frameworks/libs/systemui:view_capture",
],
resource_dirs: [
"res",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index 4db6ab6..f358ba2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -16,9 +16,6 @@
package com.android.systemui.shared.rotation;
-import static com.android.app.viewcapture.ViewCaptureFactory.getViewCaptureAwareWindowManagerInstance;
-import static com.android.systemui.Flags.enableViewCaptureTracing;
-
import android.annotation.DimenRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -33,6 +30,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
@@ -40,7 +38,6 @@
import androidx.annotation.BoolRes;
import androidx.core.view.OneShotPreDrawListener;
-import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator.Position;
/**
@@ -50,7 +47,7 @@
private static final int MARGIN_ANIMATION_DURATION_MILLIS = 300;
- private final ViewCaptureAwareWindowManager mWindowManager;
+ private final WindowManager mWindowManager;
private final ViewGroup mKeyButtonContainer;
private final FloatingRotationButtonView mKeyButtonView;
@@ -91,8 +88,7 @@
@DimenRes int taskbarBottomMargin, @DimenRes int buttonDiameter,
@DimenRes int rippleMaxWidth, @BoolRes int floatingRotationBtnPositionLeftResource) {
mContext = context;
- mWindowManager = getViewCaptureAwareWindowManagerInstance(mContext,
- enableViewCaptureTracing());
+ mWindowManager = mContext.getSystemService(WindowManager.class);
mKeyButtonContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(layout, null);
mKeyButtonView = mKeyButtonContainer.findViewById(keyButtonId);
mKeyButtonView.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 28f1381..b43d8b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -19,10 +19,8 @@
import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
-import static com.android.systemui.Flags.msdlFeedback;
import static com.android.systemui.Flags.notifyPasswordTextViewUserActivityInBackground;
-import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.os.AsyncTask;
import android.os.CountDownTimer;
@@ -37,15 +35,13 @@
import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback;
import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingClassifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.google.android.msdl.data.model.MSDLToken;
-import com.google.android.msdl.domain.MSDLPlayer;
-
import java.util.HashMap;
import java.util.Map;
@@ -62,8 +58,6 @@
protected AsyncTask<?, ?, ?> mPendingLockCheck;
protected boolean mResumed;
protected boolean mLockedOut;
- @Nullable
- protected MSDLPlayer mMSDLPlayer;
private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> {
// Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
@@ -91,16 +85,16 @@
LatencyTracker latencyTracker, FalsingCollector falsingCollector,
EmergencyButtonController emergencyButtonController,
FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor,
- @Nullable MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
- messageAreaControllerFactory, featureFlags, selectedUserInteractor);
+ messageAreaControllerFactory, featureFlags, selectedUserInteractor,
+ bouncerHapticPlayer);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
mFalsingCollector = falsingCollector;
mEmergencyButtonController = emergencyButtonController;
- mMSDLPlayer = msdlPlayer;
mUserActivityNotifier = userActivityNotifier;
}
@@ -191,7 +185,9 @@
void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) {
boolean dismissKeyguard = mSelectedUserInteractor.getSelectedUserId() == userId;
if (matched) {
- playAuthenticationHaptics(/* unlock= */true);
+ mBouncerHapticPlayer.playAuthenticationFeedback(
+ /* authenticationSucceeded = */true
+ );
getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) {
mDismissing = true;
@@ -199,7 +195,9 @@
getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode());
}
} else {
- playAuthenticationHaptics(/* unlock= */false);
+ mBouncerHapticPlayer.playAuthenticationFeedback(
+ /* authenticationSucceeded = */false
+ );
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
if (isValidPassword) {
getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
@@ -216,18 +214,6 @@
}
}
- private void playAuthenticationHaptics(boolean unlock) {
- if (!msdlFeedback() || mMSDLPlayer == null) return;
-
- MSDLToken token;
- if (unlock) {
- token = MSDLToken.UNLOCK;
- } else {
- token = MSDLToken.FAILURE;
- }
- mMSDLPlayer.playToken(token, mAuthInteractionProperties);
- }
-
protected void startErrorAnimation() { /* no-op */ }
protected void verifyPasswordAndUnlock() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 92e5432..ff78848 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -35,6 +35,7 @@
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.ui.BouncerMessageView;
import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -45,9 +46,6 @@
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.google.android.msdl.domain.InteractionProperties;
-import com.google.android.msdl.domain.MSDLPlayer;
-
import javax.inject.Inject;
/** Controller for a {@link KeyguardSecurityView}. */
@@ -66,21 +64,22 @@
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {};
private final FeatureFlags mFeatureFlags;
protected final SelectedUserInteractor mSelectedUserInteractor;
- protected final InteractionProperties mAuthInteractionProperties =
- new AuthInteractionProperties();
+ protected final BouncerHapticPlayer mBouncerHapticPlayer;
protected KeyguardInputViewController(T view, SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback,
EmergencyButtonController emergencyButtonController,
@Nullable KeyguardMessageAreaController.Factory messageAreaControllerFactory,
FeatureFlags featureFlags,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ BouncerHapticPlayer bouncerHapticPlayer) {
super(view);
mSecurityMode = securityMode;
mKeyguardSecurityCallback = keyguardSecurityCallback;
mEmergencyButtonController = emergencyButtonController;
mFeatureFlags = featureFlags;
mSelectedUserInteractor = selectedUserInteractor;
+ mBouncerHapticPlayer = bouncerHapticPlayer;
if (messageAreaControllerFactory != null) {
try {
BouncerKeyguardMessageArea kma = view.requireViewById(R.id.bouncer_message_area);
@@ -219,7 +218,7 @@
private final SelectedUserInteractor mSelectedUserInteractor;
private final UiEventLogger mUiEventLogger;
private final KeyguardKeyboardInteractor mKeyguardKeyboardInteractor;
- private final MSDLPlayer mMSDLPlayer;
+ private final BouncerHapticPlayer mBouncerHapticPlayer;
private final UserActivityNotifier mUserActivityNotifier;
@Inject
@@ -236,7 +235,7 @@
FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor,
UiEventLogger uiEventLogger,
KeyguardKeyboardInteractor keyguardKeyboardInteractor,
- MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -255,7 +254,7 @@
mSelectedUserInteractor = selectedUserInteractor;
mUiEventLogger = uiEventLogger;
mKeyguardKeyboardInteractor = keyguardKeyboardInteractor;
- mMSDLPlayer = msdlPlayer;
+ mBouncerHapticPlayer = bouncerHapticPlayer;
mUserActivityNotifier = userActivityNotifier;
}
@@ -272,7 +271,7 @@
keyguardSecurityCallback, mLatencyTracker, mFalsingCollector,
emergencyButtonController, mMessageAreaControllerFactory,
mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
- mMSDLPlayer);
+ mBouncerHapticPlayer);
} else if (keyguardInputView instanceof KeyguardPasswordView) {
return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
@@ -280,14 +279,14 @@
mInputMethodManager, emergencyButtonController, mMainExecutor, mResources,
mFalsingCollector, mKeyguardViewController,
mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
- mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier);
+ mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier);
} else if (keyguardInputView instanceof KeyguardPINView) {
return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
mLiftToActivateListener, emergencyButtonController, mFalsingCollector,
mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
- mUiEventLogger, mKeyguardKeyboardInteractor, mMSDLPlayer,
+ mUiEventLogger, mKeyguardKeyboardInteractor, mBouncerHapticPlayer,
mUserActivityNotifier);
} else if (keyguardInputView instanceof KeyguardSimPinView) {
return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
@@ -295,14 +294,14 @@
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
emergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
- mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier);
+ mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier);
} else if (keyguardInputView instanceof KeyguardSimPukView) {
return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
emergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
- mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier
+ mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier
);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 905fa09..4628ed7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -19,7 +19,6 @@
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -48,6 +47,7 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
import com.android.systemui.Flags;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -56,8 +56,6 @@
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.google.android.msdl.domain.MSDLPlayer;
-
import java.util.List;
public class KeyguardPasswordViewController
@@ -138,12 +136,12 @@
FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor,
KeyguardKeyboardInteractor keyguardKeyboardInteractor,
- @Nullable MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, falsingCollector,
- emergencyButtonController, featureFlags, selectedUserInteractor, msdlPlayer,
- userActivityNotifier);
+ emergencyButtonController, featureFlags, selectedUserInteractor,
+ bouncerHapticPlayer, userActivityNotifier);
mKeyguardSecurityCallback = keyguardSecurityCallback;
mInputMethodManager = inputMethodManager;
mPostureController = postureController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index f74d93e..7fb6664 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -36,7 +36,7 @@
import com.android.internal.widget.LockscreenCredential;
import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.bouncer.ui.helper.BouncerHapticHelper;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingClassifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
@@ -44,8 +44,6 @@
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.google.android.msdl.domain.MSDLPlayer;
-
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -70,7 +68,6 @@
private LockPatternView mLockPatternView;
private CountDownTimer mCountdownTimer;
private AsyncTask<?, ?, ?> mPendingLockCheck;
- private MSDLPlayer mMSDLPlayer;
private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() {
@Override
@@ -80,7 +77,7 @@
};
private final LockPatternView.ExternalHapticsPlayer mExternalHapticsPlayer = () -> {
- BouncerHapticHelper.INSTANCE.playPatternDotFeedback(mMSDLPlayer, mView);
+ mBouncerHapticPlayer.playPatternDotFeedback(mView);
};
/**
@@ -174,9 +171,8 @@
boolean isValidPattern) {
boolean dismissKeyguard = mSelectedUserInteractor.getSelectedUserId() == userId;
if (matched) {
- BouncerHapticHelper.INSTANCE.playMSDLAuthenticationFeedback(
- /* authenticationSucceeded= */true,
- /* player =*/mMSDLPlayer
+ mBouncerHapticPlayer.playAuthenticationFeedback(
+ /* authenticationSucceeded= */true
);
getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) {
@@ -185,9 +181,8 @@
getKeyguardSecurityCallback().dismiss(true, userId, SecurityMode.Pattern);
}
} else {
- BouncerHapticHelper.INSTANCE.playMSDLAuthenticationFeedback(
- /* authenticationSucceeded= */false,
- /* player =*/mMSDLPlayer
+ mBouncerHapticPlayer.playAuthenticationFeedback(
+ /* authenticationSucceeded= */false
);
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
if (isValidPattern) {
@@ -216,9 +211,11 @@
EmergencyButtonController emergencyButtonController,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
DevicePostureController postureController, FeatureFlags featureFlags,
- SelectedUserInteractor selectedUserInteractor, MSDLPlayer msdlPlayer) {
+ SelectedUserInteractor selectedUserInteractor, BouncerHapticPlayer bouncerHapticPlayer
+ ) {
super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
- messageAreaControllerFactory, featureFlags, selectedUserInteractor);
+ messageAreaControllerFactory, featureFlags, selectedUserInteractor,
+ bouncerHapticPlayer);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
@@ -228,7 +225,6 @@
featureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE));
mLockPatternView = mView.findViewById(R.id.lockPatternView);
mPostureController = postureController;
- mMSDLPlayer = msdlPlayer;
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index f575cf2..d999994 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -16,11 +16,9 @@
package com.android.keyguard;
-import static com.android.systemui.Flags.msdlFeedback;
import static com.android.systemui.Flags.pinInputFieldStyledFocusState;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
-import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
@@ -37,14 +35,12 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
import com.android.systemui.Flags;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.google.android.msdl.data.model.MSDLToken;
-import com.google.android.msdl.domain.MSDLPlayer;
-
public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
extends KeyguardAbsKeyInputViewController<T> {
@@ -83,12 +79,12 @@
FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor,
KeyguardKeyboardInteractor keyguardKeyboardInteractor,
- @Nullable MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, falsingCollector,
- emergencyButtonController, featureFlags, selectedUserInteractor, msdlPlayer,
- userActivityNotifier);
+ emergencyButtonController, featureFlags, selectedUserInteractor,
+ bouncerHapticPlayer, userActivityNotifier);
mLiftToActivateListener = liftToActivateListener;
mFalsingCollector = falsingCollector;
mKeyguardKeyboardInteractor = keyguardKeyboardInteractor;
@@ -110,16 +106,16 @@
return false;
});
button.setAnimationEnabled(showAnimations);
- button.setMSDLPlayer(mMSDLPlayer);
+ button.setBouncerHapticHelper(mBouncerHapticPlayer);
}
mPasswordEntry.setOnKeyListener(mOnKeyListener);
mPasswordEntry.setUserActivityListener(this::onUserInput);
View deleteButton = mView.findViewById(R.id.delete_button);
- if (msdlFeedback()) {
+ if (mBouncerHapticPlayer.isEnabled()) {
deleteButton.setOnTouchListener((View view, MotionEvent event) -> {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mMSDLPlayer != null) {
- mMSDLPlayer.playToken(MSDLToken.KEYPRESS_DELETE, null);
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mBouncerHapticPlayer.playDeleteKeyPressFeedback();
}
return false;
});
@@ -137,8 +133,8 @@
if (mPasswordEntry.isEnabled()) {
mView.resetPasswordText(true /* animate */, true /* announce */);
}
- if (msdlFeedback() && mMSDLPlayer != null) {
- mMSDLPlayer.playToken(MSDLToken.LONG_PRESS, null);
+ if (mBouncerHapticPlayer.isEnabled()) {
+ mBouncerHapticPlayer.playDeleteKeyLongPressedFeedback();
} else {
mView.doHapticKeyClick();
}
@@ -147,7 +143,7 @@
View okButton = mView.findViewById(R.id.key_enter);
if (okButton != null) {
- if (!msdlFeedback()) {
+ if (!mBouncerHapticPlayer.isEnabled()) {
okButton.setOnTouchListener(mActionButtonTouchListener);
}
okButton.setOnClickListener(v -> {
@@ -201,7 +197,7 @@
for (NumPadKey button : mView.getButtons()) {
button.setOnTouchListener(null);
- button.setMSDLPlayer(null);
+ button.setBouncerHapticHelper(null);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 3b5bf1a..d3c02e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -18,7 +18,6 @@
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
-import android.annotation.Nullable;
import android.view.View;
import com.android.internal.logging.UiEvent;
@@ -27,6 +26,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -34,8 +34,6 @@
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.google.android.msdl.domain.MSDLPlayer;
-
public class KeyguardPinViewController
extends KeyguardPinBasedInputViewController<KeyguardPINView> {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -65,12 +63,12 @@
DevicePostureController postureController, FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger,
KeyguardKeyboardInteractor keyguardKeyboardInteractor,
- @Nullable MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
- keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier);
+ keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mPostureController = postureController;
mLockPatternUtils = lockPatternUtils;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 47fe2b2..1c1acf8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -21,7 +21,6 @@
import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
@@ -44,13 +43,12 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.google.android.msdl.domain.MSDLPlayer;
-
public class KeyguardSimPinViewController
extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
public static final String TAG = "KeyguardSimPinView";
@@ -99,12 +97,12 @@
EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor,
KeyguardKeyboardInteractor keyguardKeyboardInteractor,
- @Nullable MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
- keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier);
+ keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mTelephonyManager = telephonyManager;
mSimImageView = mView.findViewById(R.id.keyguard_sim);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index c688acb..9adc5ba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -17,7 +17,6 @@
package com.android.keyguard;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -39,13 +38,12 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.google.android.msdl.domain.MSDLPlayer;
-
public class KeyguardSimPukViewController
extends KeyguardPinBasedInputViewController<KeyguardSimPukView> {
private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -96,12 +94,12 @@
EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor,
KeyguardKeyboardInteractor keyguardKeyboardInteractor,
- @Nullable MSDLPlayer msdlPlayer,
+ BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
- keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier);
+ keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mTelephonyManager = telephonyManager;
mSimImageView = mView.findViewById(R.id.keyguard_sim);
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 4fb80de..7fe4ec8 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -15,7 +15,6 @@
*/
package com.android.keyguard;
-import static com.android.systemui.Flags.msdlFeedback;
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
import android.content.Context;
@@ -37,11 +36,9 @@
import androidx.annotation.Nullable;
import com.android.settingslib.Utils;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.res.R;
-import com.google.android.msdl.data.model.MSDLToken;
-import com.google.android.msdl.domain.MSDLPlayer;
-
/**
* Viewgroup for the bouncer numpad button, specifically for digits.
*/
@@ -62,7 +59,7 @@
private NumPadAnimator mAnimator;
private int mOrientation;
@Nullable
- private MSDLPlayer mMSDLPlayer;
+ private BouncerHapticPlayer mBouncerHapticPlayer;
private View.OnClickListener mListener = new View.OnClickListener() {
@Override
@@ -227,8 +224,8 @@
// Cause a VIRTUAL_KEY vibration
public void doHapticKeyClick() {
- if (msdlFeedback() && mMSDLPlayer != null) {
- mMSDLPlayer.playToken(MSDLToken.KEYPRESS_STANDARD, null);
+ if (mBouncerHapticPlayer != null && mBouncerHapticPlayer.isEnabled()) {
+ mBouncerHapticPlayer.playNumpadKeyFeedback();
} else {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -255,7 +252,7 @@
info.setTextEntryKey(true);
}
- public void setMSDLPlayer(@Nullable MSDLPlayer player) {
- mMSDLPlayer = player;
+ public void setBouncerHapticHelper(@Nullable BouncerHapticPlayer bouncerHapticPlayer) {
+ mBouncerHapticPlayer = bouncerHapticPlayer;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
index aa96231..d4e74d3 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
@@ -54,6 +54,7 @@
STATUS_ICON_MIC_CAMERA_DISABLED,
STATUS_ICON_PRIORITY_MODE_ON,
STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
+ STATUS_ICON_LOCATION_ACTIVE,
})
public @interface StatusIconType {}
public static final int STATUS_ICON_NOTIFICATIONS = 0;
@@ -64,6 +65,7 @@
public static final int STATUS_ICON_MIC_CAMERA_DISABLED = 5;
public static final int STATUS_ICON_PRIORITY_MODE_ON = 6;
public static final int STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE = 7;
+ public static final int STATUS_ICON_LOCATION_ACTIVE = 8;
private final Map<Integer, View> mStatusIcons = new HashMap<>();
private Context mContext;
@@ -136,6 +138,8 @@
addDoubleShadow(fetchStatusIconForResId(R.id.dream_overlay_priority_mode)));
mStatusIcons.put(STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
fetchStatusIconForResId(R.id.dream_overlay_assistant_attention_indicator));
+ mStatusIcons.put(STATUS_ICON_LOCATION_ACTIVE,
+ fetchStatusIconForResId(R.id.dream_overlay_location_active));
mSystemStatusViewGroup = findViewById(R.id.dream_overlay_system_status);
mExtraSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
@@ -151,6 +155,7 @@
case STATUS_ICON_MIC_CAMERA_DISABLED -> "mic_camera_disabled";
case STATUS_ICON_PRIORITY_MODE_ON -> "priority_mode_on";
case STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE -> "assistant_attention_active";
+ case STATUS_ICON_LOCATION_ACTIVE -> "location_active";
default -> type + "(unknown)";
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
index 04595a2..75024c6 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
@@ -27,6 +27,7 @@
import android.util.PluralsMessageFormatter;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -39,6 +40,9 @@
import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.dagger.DreamLog;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -79,6 +83,7 @@
private final DreamOverlayStateController mDreamOverlayStateController;
private final UserTracker mUserTracker;
private final WifiInteractor mWifiInteractor;
+ private final PrivacyItemController mPrivacyItemController;
private final StatusBarWindowStateController mStatusBarWindowStateController;
private final DreamOverlayStatusBarItemsProvider mStatusBarItemsProvider;
private final Executor mMainExecutor;
@@ -131,6 +136,9 @@
private final StatusBarWindowStateListener mStatusBarWindowStateListener =
this::onSystemStatusBarStateChanged;
+ private final PrivacyItemController.Callback mPrivacyItemControllerCallback =
+ this::onPrivacyItemsChanged;
+
@Inject
public AmbientStatusBarViewController(
AmbientStatusBarView view,
@@ -147,6 +155,7 @@
DreamOverlayStateController dreamOverlayStateController,
UserTracker userTracker,
WifiInteractor wifiInteractor,
+ PrivacyItemController privacyItemController,
CommunalSceneInteractor communalSceneInteractor,
@DreamLog LogBuffer logBuffer) {
super(view);
@@ -163,6 +172,7 @@
mDreamOverlayStateController = dreamOverlayStateController;
mUserTracker = userTracker;
mWifiInteractor = wifiInteractor;
+ mPrivacyItemController = privacyItemController;
mCommunalSceneInteractor = communalSceneInteractor;
mLogger = new DreamLogger(logBuffer, TAG);
}
@@ -174,10 +184,12 @@
// Register to receive show/hide updates for the system status bar. Our custom status bar
// needs to hide when the system status bar is showing to ovoid overlapping status bars.
mStatusBarWindowStateController.addListener(mStatusBarWindowStateListener);
+ mPrivacyItemController.addCallback(mPrivacyItemControllerCallback);
}
@Override
public void destroy() {
+ mPrivacyItemController.removeCallback(mPrivacyItemControllerCallback);
mStatusBarWindowStateController.removeListener(mStatusBarWindowStateListener);
super.destroy();
@@ -274,6 +286,11 @@
R.string.wifi_unavailable_dream_overlay_content_description);
}
+ void updateLocationStatusIcon(boolean enabled) {
+ showIcon(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE, enabled,
+ R.string.location_active_dream_overlay_content_description);
+ }
+
private void updateAlarmStatusIcon() {
final AlarmManager.AlarmClockInfo alarm =
mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
@@ -369,6 +386,11 @@
mMainExecutor.execute(this::updateVisibility);
}
+ private void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
+ updateLocationStatusIcon(privacyItems.stream()
+ .anyMatch(item -> item.getPrivacyType() == PrivacyType.TYPE_LOCATION));
+ }
+
private void onStatusBarItemsChanged(List<StatusBarItem> newItems) {
mMainExecutor.execute(() -> {
mExtraStatusBarItems.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index c28bce2..6d6cd45 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -294,7 +294,9 @@
/** Tell the bouncer that bouncer is requested when device is already authenticated */
fun notifyUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
- applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
+ applicationScope.launch {
+ repository.setUserRequestedBouncerWhenAlreadyAuthenticated(userId)
+ }
}
/** Tell the bouncer that keyguard is authenticated with biometrics. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
index d7a4863b..7647cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.shared.flag
import com.android.systemui.Flags
+import com.android.systemui.flags.RefactorFlagUtils
import com.android.systemui.scene.shared.flag.SceneContainerFlag
object ComposeBouncerFlags {
@@ -34,6 +35,18 @@
}
/**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(
+ isEnabled,
+ "SceneContainerFlag || ComposeBouncerFlag"
+ )
+
+ /**
* Returns `true` if only compose bouncer is enabled and scene container framework is not
* enabled.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt
deleted file mode 100644
index 1faacff..0000000
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bouncer.ui.helper
-
-import android.view.HapticFeedbackConstants
-import android.view.View
-import com.android.keyguard.AuthInteractionProperties
-import com.android.systemui.Flags
-//noinspection CleanArchitectureDependencyViolation: Data layer only referenced for this enum class
-import com.google.android.msdl.data.model.MSDLToken
-import com.google.android.msdl.domain.MSDLPlayer
-
-/** A helper object to deliver haptic feedback in bouncer interactions. */
-object BouncerHapticHelper {
-
- private val authInteractionProperties = AuthInteractionProperties()
-
- /**
- * Deliver MSDL feedback as a result of authenticating through a bouncer.
- *
- * @param[authenticationSucceeded] Whether the authentication was successful or not.
- * @param[player] The [MSDLPlayer] that delivers the correct feedback.
- */
- fun playMSDLAuthenticationFeedback(
- authenticationSucceeded: Boolean,
- player: MSDLPlayer?,
- ) {
- if (player == null || !Flags.msdlFeedback()) {
- return
- }
-
- val token =
- if (authenticationSucceeded) {
- MSDLToken.UNLOCK
- } else {
- MSDLToken.FAILURE
- }
- player.playToken(token, authInteractionProperties)
- }
-
- /**
- * Deliver feedback when dragging through cells in the pattern bouncer. This function can play
- * MSDL feedback using a [MSDLPlayer], or fallback to a default haptic feedback using the
- * [View.performHapticFeedback] API and a [View].
- *
- * @param[player] [MSDLPlayer] for MSDL feedback.
- * @param[view] A [View] for default haptic feedback using [View.performHapticFeedback]
- */
- fun playPatternDotFeedback(player: MSDLPlayer?, view: View?) {
- if (player == null || !Flags.msdlFeedback()) {
- view?.performHapticFeedback(
- HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING,
- )
- } else {
- player.playToken(MSDLToken.DRAG_INDICATOR)
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt
new file mode 100644
index 0000000..19e7537
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bouncer.ui.helper
+
+import android.view.HapticFeedbackConstants
+import android.view.View
+import com.android.keyguard.AuthInteractionProperties
+import com.android.systemui.Flags
+//noinspection CleanArchitectureDependencyViolation: Data layer only referenced for this enum class
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.MSDLPlayer
+import javax.inject.Inject
+
+/**
+ * A helper class to deliver haptic feedback in bouncer interactions.
+ *
+ * @param[msdlPlayer] The [MSDLPlayer] used to deliver MSDL feedback.
+ */
+class BouncerHapticPlayer @Inject constructor(private val msdlPlayer: dagger.Lazy<MSDLPlayer>) {
+
+ private val authInteractionProperties by
+ lazy(LazyThreadSafetyMode.NONE) { AuthInteractionProperties() }
+
+ val isEnabled: Boolean
+ get() = Flags.msdlFeedback()
+
+ /**
+ * Deliver MSDL feedback as a result of authenticating through a bouncer.
+ *
+ * @param[authenticationSucceeded] Whether the authentication was successful or not.
+ */
+ fun playAuthenticationFeedback(authenticationSucceeded: Boolean) {
+ if (!isEnabled) return
+
+ val token =
+ if (authenticationSucceeded) {
+ MSDLToken.UNLOCK
+ } else {
+ MSDLToken.FAILURE
+ }
+ msdlPlayer.get().playToken(token, authInteractionProperties)
+ }
+
+ /**
+ * Deliver feedback when dragging through cells in the pattern bouncer. This function can play
+ * MSDL feedback using a [MSDLPlayer], or fallback to a default haptic feedback using the
+ * [View.performHapticFeedback] API and a [View].
+ *
+ * @param[view] A [View] for default haptic feedback using [View.performHapticFeedback]
+ */
+ fun playPatternDotFeedback(view: View?) {
+ if (!isEnabled) {
+ view?.performHapticFeedback(
+ HapticFeedbackConstants.VIRTUAL_KEY,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING,
+ )
+ } else {
+ msdlPlayer.get().playToken(MSDLToken.DRAG_INDICATOR)
+ }
+ }
+
+ /** Deliver MSDL feedback when the delete key of the pin bouncer is pressed */
+ fun playDeleteKeyPressFeedback() = msdlPlayer.get().playToken(MSDLToken.KEYPRESS_DELETE)
+
+ /**
+ * Deliver MSDL feedback when the delete key of the pin bouncer is long-pressed
+ *
+ * @return whether MSDL feedback is allowed to play.
+ */
+ fun playDeleteKeyLongPressedFeedback() = msdlPlayer.get().playToken(MSDLToken.LONG_PRESS)
+
+ /** Deliver MSDL feedback when a numpad key is pressed on the pin bouncer */
+ fun playNumpadKeyFeedback() = msdlPlayer.get().playToken(MSDLToken.KEYPRESS_STANDARD)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
index d223657..c60f932 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
@@ -17,12 +17,14 @@
package com.android.systemui.bouncer.ui.viewmodel
import androidx.compose.runtime.getValue
-import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.kotlin.Utils.Companion.sample
+import com.android.systemui.util.kotlin.sample
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.coroutineScope
@@ -34,7 +36,7 @@
private val legacyInteractor: PrimaryBouncerInteractor,
private val authenticationInteractor: AuthenticationInteractor,
private val selectedUserInteractor: SelectedUserInteractor,
- private val viewMediatorCallback: ViewMediatorCallback?,
+ private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
) : ExclusiveActivatable() {
private val hydrator = Hydrator("BouncerContainerViewModel")
@@ -45,23 +47,23 @@
override suspend fun onActivated(): Nothing {
coroutineScope {
launch {
+ legacyInteractor.isShowing
+ .sample(deviceUnlockedInteractor.deviceUnlockStatus, ::Pair)
+ .collect { (isShowing, unlockStatus) ->
+ if (isShowing && unlockStatus.isUnlocked) {
+ legacyInteractor.notifyUserRequestedBouncerWhenAlreadyAuthenticated(
+ selectedUserInteractor.getSelectedUserId()
+ )
+ }
+ }
+ }
+
+ launch {
authenticationInteractor.onAuthenticationResult.collect { authenticationSucceeded ->
if (authenticationSucceeded) {
- // Some dismiss actions require that keyguard be dismissed right away or
- // deferred until something else later on dismisses keyguard (eg. end of
- // a hide animation).
- val deferKeyguardDone =
- legacyInteractor.bouncerDismissAction?.onDismissAction?.onDismiss()
- legacyInteractor.setDismissAction(null, null)
-
- viewMediatorCallback?.let {
- val selectedUserId = selectedUserInteractor.getSelectedUserId()
- if (deferKeyguardDone == true) {
- it.keyguardDonePending(selectedUserId)
- } else {
- it.keyguardDone(selectedUserId)
- }
- }
+ legacyInteractor.notifyKeyguardAuthenticatedPrimaryAuth(
+ selectedUserInteractor.getSelectedUserId()
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index df6ca9b..da29c62 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -31,6 +31,7 @@
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
+import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.res.R
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -265,6 +266,15 @@
}
}
+ /** Notifies that the user has pressed down on a digit button. */
+ fun onDigitButtonDown() {
+ if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
+ // Current PIN bouncer informs FalsingInteractor#avoidGesture() upon every Pin button
+ // touch.
+ super.onDown()
+ }
+ }
+
@AssistedFactory
interface Factory {
fun create(
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index dcd4195..a62600d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -25,6 +25,7 @@
public class FalsingCollectorFake implements FalsingCollector {
public KeyEvent lastKeyEvent = null;
+ public boolean avoidGestureInvoked = false;
@Override
public void init() {
@@ -87,6 +88,16 @@
@Override
public void avoidGesture() {
+ avoidGestureInvoked = true;
+ }
+
+ /**
+ * @return whether {@link #avoidGesture()} was invoked.
+ */
+ public boolean wasLastGestureAvoided() {
+ boolean wasLastGestureAvoided = avoidGestureInvoked;
+ avoidGestureInvoked = false;
+ return wasLastGestureAvoided;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index b570e14..a687734 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -117,7 +117,7 @@
sceneInteractor: SceneInteractor,
@CommunalLog logBuffer: LogBuffer,
@CommunalTableLog tableLogBuffer: TableLogBuffer,
- private val managedProfileController: ManagedProfileController
+ private val managedProfileController: ManagedProfileController,
) {
private val logger = Logger(logBuffer, "CommunalInteractor")
@@ -154,7 +154,7 @@
allOf(
communalSettingsInteractor.isCommunalEnabled,
not(keyguardInteractor.isEncryptedOrLockdown),
- keyguardInteractor.isKeyguardShowing
+ keyguardInteractor.isKeyguardShowing,
)
.distinctUntilChanged()
.onEach { available ->
@@ -342,7 +342,7 @@
fun changeScene(
newScene: SceneKey,
loggingReason: String,
- transitionKey: TransitionKey? = null
+ transitionKey: TransitionKey? = null,
) = communalSceneInteractor.changeScene(newScene, loggingReason, transitionKey)
fun setEditModeOpen(isOpen: Boolean) {
@@ -354,9 +354,7 @@
}
/** Show the widget editor Activity. */
- fun showWidgetEditor(
- shouldOpenWidgetPickerOnStart: Boolean = false,
- ) {
+ fun showWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean = false) {
communalSceneInteractor.setEditModeState(EditModeState.STARTING)
editWidgetsActivityStarter.startActivity(shouldOpenWidgetPickerOnStart)
}
@@ -419,7 +417,7 @@
IntentFilter().apply {
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- },
+ }
)
.emitOnStart()
@@ -450,7 +448,7 @@
rank = widget.rank,
providerInfo = widget.providerInfo,
appWidgetHost = appWidgetHost,
- inQuietMode = isQuietModeEnabled(widget.providerInfo.profile)
+ inQuietMode = isQuietModeEnabled(widget.providerInfo.profile),
)
}
is CommunalWidgetContentModel.Pending -> {
@@ -468,7 +466,7 @@
/** Filter widgets based on whether their associated profile is allowed by device policy. */
private fun filterWidgetsAllowedByDevicePolicy(
list: List<CommunalWidgetContentModel>,
- disallowedByDevicePolicyUser: UserInfo?
+ disallowedByDevicePolicyUser: UserInfo?,
): List<CommunalWidgetContentModel> =
if (disallowedByDevicePolicyUser == null) {
list
@@ -507,7 +505,7 @@
* A flow of ongoing content, including smartspace timers and umo, ordered by creation time and
* sized dynamically.
*/
- val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> =
+ fun ongoingContent(isMediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> =
combine(smartspaceRepository.timers, mediaRepository.mediaModel) { timers, media ->
val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>()
@@ -523,22 +521,20 @@
)
// Add UMO
- if (media.hasAnyMediaOrRecommendation) {
+ if (isMediaHostVisible && media.hasAnyMediaOrRecommendation) {
ongoingContent.add(
CommunalContentModel.Umo(
- createdTimestampMillis = media.createdTimestampMillis,
+ createdTimestampMillis = media.createdTimestampMillis
)
)
}
- // Order by creation time descending
+ // Order by creation time descending.
ongoingContent.sortByDescending { it.createdTimestampMillis }
+ // Resize the items.
+ ongoingContent.resizeItems()
- // Dynamic sizing
- ongoingContent.forEachIndexed { index, model ->
- model.size = dynamicContentSize(ongoingContent.size, index)
- }
-
+ // Return the sorted and resized items.
ongoingContent
}
.flowOn(bgDispatcher)
@@ -548,7 +544,7 @@
* stale data following user deletion.
*/
private fun filterWidgetsByExistingUsers(
- list: List<CommunalWidgetContentModel>,
+ list: List<CommunalWidgetContentModel>
): List<CommunalWidgetContentModel> {
val currentUserIds = userTracker.userProfiles.map { it.id }.toSet()
return list.filter { widget ->
@@ -560,6 +556,40 @@
}
}
+ // Dynamically resizes the height of items in the list of ongoing items such that they fit in
+ // columns in as compact a space as possible.
+ //
+ // Currently there are three possible sizes. When the total number is 1, size for that content
+ // is [FULL], when the total number is 2, size for each is [HALF], and 3, size for each is
+ // [THIRD].
+ //
+ // This algorithm also respects each item's minimum size. All items in a column will have the
+ // same size, and all items in a column will be no smaller than any item's minimum size.
+ private fun List<CommunalContentModel.Ongoing>.resizeItems() {
+ fun resizeColumn(c: List<CommunalContentModel.Ongoing>) {
+ if (c.isEmpty()) return
+ val newSize = CommunalContentSize.toSize(span = FULL.span / c.size)
+ c.forEach { item -> item.size = newSize }
+ }
+
+ val column = mutableListOf<CommunalContentModel.Ongoing>()
+ var available = FULL.span
+
+ forEach { item ->
+ if (available < item.minSize.span) {
+ resizeColumn(column)
+ column.clear()
+ available = FULL.span
+ }
+
+ column.add(item)
+ available -= item.minSize.span
+ }
+
+ // Make sure to resize the final column.
+ resizeColumn(column)
+ }
+
companion object {
const val TAG = "CommunalInteractor"
@@ -574,31 +604,6 @@
* of -1 means that the user's chosen screen timeout will be used instead.
*/
const val AWAKE_INTERVAL_MS = -1
-
- /**
- * Calculates the content size dynamically based on the total number of contents of that
- * type.
- *
- * Contents with the same type are expected to fill each column evenly. Currently there are
- * three possible sizes. When the total number is 1, size for that content is [FULL], when
- * the total number is 2, size for each is [HALF], and 3, size for each is [THIRD].
- *
- * When dynamic contents fill in multiple columns, the first column follows the algorithm
- * above, and the remaining contents are packed in [THIRD]s. For example, when the total
- * number if 4, the first one is [FULL], filling the column, and the remaining 3 are
- * [THIRD].
- *
- * @param size The total number of contents of this type.
- * @param index The index of the current content of this type.
- */
- private fun dynamicContentSize(size: Int, index: Int): CommunalContentSize {
- val remainder = size % CommunalContentSize.entries.size
- return CommunalContentSize.toSize(
- span =
- FULL.span /
- if (index > remainder - 1) CommunalContentSize.entries.size else remainder
- )
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index ac496f0..3826fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -24,11 +24,14 @@
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
import com.android.systemui.communal.shared.log.CommunalSceneLogger
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.communal.shared.model.CommunalTransitionKeys
+import com.android.systemui.communal.shared.model.CommunalScenes.toSceneContainerSceneKey
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.pairwiseBy
import javax.inject.Inject
@@ -45,6 +48,7 @@
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
@@ -55,6 +59,7 @@
@Application private val applicationScope: CoroutineScope,
private val repository: CommunalSceneRepository,
private val logger: CommunalSceneLogger,
+ private val sceneInteractor: SceneInteractor,
) {
private val _isLaunchingWidget = MutableStateFlow(false)
@@ -72,8 +77,14 @@
private val onSceneAboutToChangeListener = mutableSetOf<OnSceneAboutToChangeListener>()
- /** Registers a listener which is called when the scene is about to change. */
+ /**
+ * Registers a listener which is called when the scene is about to change.
+ *
+ * This API is for legacy communal container scenes, and should not be used when
+ * [SceneContainerFlag] is enabled.
+ */
fun registerSceneStateProcessor(processor: OnSceneAboutToChangeListener) {
+ SceneContainerFlag.assertInLegacyMode()
onSceneAboutToChangeListener.add(processor)
}
@@ -87,6 +98,15 @@
transitionKey: TransitionKey? = null,
keyguardState: KeyguardState? = null,
) {
+ if (SceneContainerFlag.isEnabled) {
+ return sceneInteractor.changeScene(
+ toScene = newScene.toSceneContainerSceneKey(),
+ loggingReason = loggingReason,
+ transitionKey = transitionKey,
+ sceneState = keyguardState,
+ )
+ }
+
applicationScope.launch("$TAG#changeScene") {
if (currentScene.value == newScene) return@launch
logger.logSceneChangeRequested(
@@ -107,6 +127,13 @@
delayMillis: Long = 0,
keyguardState: KeyguardState? = null
) {
+ if (SceneContainerFlag.isEnabled) {
+ return sceneInteractor.snapToScene(
+ toScene = newScene.toSceneContainerSceneKey(),
+ loggingReason = loggingReason,
+ )
+ }
+
applicationScope.launch("$TAG#snapToScene") {
delay(delayMillis)
if (currentScene.value == newScene) return@launch
@@ -125,37 +152,27 @@
onSceneAboutToChangeListener.forEach { it.onSceneAboutToChange(newScene, keyguardState) }
}
- /** Changes to Blank scene when starting an activity after dismissing keyguard. */
- fun changeSceneForActivityStartOnDismissKeyguard() {
- // skip if we're starting edit mode activity, as it will be handled later by changeScene
- // with transition key [CommunalTransitionKeys.ToEditMode].
- if (_editModeState.value == EditModeState.STARTING) {
- return
- }
- changeScene(
- CommunalScenes.Blank,
- "activity start dismissing keyguard",
- CommunalTransitionKeys.SimpleFade,
- )
- }
-
/**
* Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
*/
val currentScene: StateFlow<SceneKey> =
- repository.currentScene
- .pairwiseBy(initialValue = repository.currentScene.value) { from, to ->
- logger.logSceneChangeCommitted(
- from = from,
- to = to,
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.currentScene
+ } else {
+ repository.currentScene
+ .pairwiseBy(initialValue = repository.currentScene.value) { from, to ->
+ logger.logSceneChangeCommitted(
+ from = from,
+ to = to,
+ )
+ to
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = repository.currentScene.value,
)
- to
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = repository.currentScene.value,
- )
+ }
private val _editModeState = MutableStateFlow<EditModeState?>(null)
/**
@@ -170,13 +187,17 @@
/** Transition state of the hub mode. */
val transitionState: StateFlow<ObservableTransitionState> =
- repository.transitionState
- .onEach { logger.logSceneTransition(it) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = repository.transitionState.value,
- )
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.transitionState
+ } else {
+ repository.transitionState
+ .onEach { logger.logSceneTransition(it) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = repository.transitionState.value,
+ )
+ }
/**
* Updates the transition state of the hub [SceneTransitionLayout].
@@ -184,10 +205,19 @@
* Note that you must call is with `null` when the UI is done or risk a memory leak.
*/
fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
- repository.setTransitionState(transitionState)
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.setTransitionState(transitionState)
+ } else {
+ repository.setTransitionState(transitionState)
+ }
}
- /** Returns a flow that tracks the progress of transitions to the given scene from 0-1. */
+ /**
+ * Returns a flow that tracks the progress of transitions to the given scene from 0-1.
+ *
+ * This API is for legacy communal container scenes, and should not be used when
+ * [SceneContainerFlag] is enabled.
+ */
fun transitionProgressToScene(targetScene: SceneKey) =
transitionState
.flatMapLatest { state ->
@@ -209,6 +239,7 @@
}
}
.distinctUntilChanged()
+ .onStart { SceneContainerFlag.assertInLegacyMode() }
/**
* Flow that emits a boolean if the communal UI is fully visible and not in transition.
@@ -219,7 +250,10 @@
val isIdleOnCommunal: StateFlow<Boolean> =
transitionState
.map {
- it is ObservableTransitionState.Idle && it.currentScene == CommunalScenes.Communal
+ it is ObservableTransitionState.Idle &&
+ (it.currentScene ==
+ if (SceneContainerFlag.isEnabled) Scenes.Communal
+ else CommunalScenes.Communal)
}
.stateIn(
scope = applicationScope,
@@ -239,7 +273,13 @@
val isCommunalVisible: StateFlow<Boolean> =
transitionState
.map {
- !(it is ObservableTransitionState.Idle && it.currentScene == CommunalScenes.Blank)
+ if (SceneContainerFlag.isEnabled)
+ it is ObservableTransitionState.Idle && it.currentScene == Scenes.Communal ||
+ (it is ObservableTransitionState.Transition &&
+ (it.fromContent == Scenes.Communal || it.toContent == Scenes.Communal))
+ else
+ !(it is ObservableTransitionState.Idle &&
+ it.currentScene == CommunalScenes.Blank)
}
.stateIn(
scope = applicationScope,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 4c821d4..c2f6e85 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -34,12 +34,18 @@
/** Size to be rendered in the grid. */
val size: CommunalContentSize
+ /** The minimum size content can be resized to. */
+ val minSize: CommunalContentSize
+ get() = CommunalContentSize.HALF
+
/**
* A type of communal content is ongoing / live / ephemeral, and can be sized and ordered
* dynamically.
*/
sealed interface Ongoing : CommunalContentModel {
override var size: CommunalContentSize
+ override val minSize
+ get() = CommunalContentSize.THIRD
/** Timestamp in milliseconds of when the content was created. */
val createdTimestampMillis: Long
@@ -72,7 +78,7 @@
data class DisabledWidget(
override val appWidgetId: Int,
override val rank: Int,
- val providerInfo: AppWidgetProviderInfo
+ val providerInfo: AppWidgetProviderInfo,
) : WidgetContent {
override val key = KEY.disabledWidget(appWidgetId)
override val componentName: ComponentName = providerInfo.provider
@@ -109,10 +115,7 @@
override val size = CommunalContentSize.HALF
}
- class Tutorial(
- id: Int,
- override var size: CommunalContentSize,
- ) : CommunalContentModel {
+ class Tutorial(id: Int, override var size: CommunalContentSize) : CommunalContentModel {
override val key = KEY.tutorial(id)
}
@@ -128,6 +131,7 @@
class Umo(
override val createdTimestampMillis: Long,
override var size: CommunalContentSize = CommunalContentSize.HALF,
+ override var minSize: CommunalContentSize = CommunalContentSize.HALF,
) : Ongoing {
override val key = KEY.umo()
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
index d5a56c1..e562dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
@@ -17,6 +17,8 @@
package com.android.systemui.communal.shared.model
import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
/** Definition of the possible scenes for the communal UI. */
object CommunalScenes {
@@ -27,4 +29,30 @@
@JvmField val Communal = SceneKey("communal")
@JvmField val Default = Blank
+
+ private fun SceneKey.isCommunalScene(): Boolean {
+ return this == Blank || this == Communal
+ }
+
+ /**
+ * Maps a legacy communal scene to a scene in the scene container.
+ *
+ * The rules are simple:
+ * - A legacy communal scene maps to a communal scene in the Scene Transition Framework (STF).
+ * - A legacy blank scene means that the communal scene layout does not render anything so
+ * whatever is beneath the layout is shown. That usually means lockscreen or dream, both of
+ * which are represented by the lockscreen scene in STF (but different keyguard states in
+ * KTF).
+ */
+ fun SceneKey.toSceneContainerSceneKey(): SceneKey {
+ if (!isCommunalScene() || !SceneContainerFlag.isEnabled) {
+ return this
+ }
+
+ return when (this) {
+ Communal -> Scenes.Communal
+ Blank -> Scenes.Lockscreen
+ else -> throw Throwable("Unrecognized communal scene: $this")
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index d69ba1b..53109ac 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -125,15 +125,9 @@
private var frozenCommunalContent: List<CommunalContentModel>? = null
private val ongoingContent =
- combine(
- isMediaHostVisible,
- communalInteractor.ongoingContent.onEach { mediaHost.updateViewVisibility() }
- ) { mediaVisible, ongoingContent ->
- if (mediaVisible) {
- ongoingContent
- } else {
- // Media is not visible, don't show UMO
- ongoingContent.filterNot { it is CommunalContentModel.Umo }
+ isMediaHostVisible.flatMapLatest { isMediaHostVisible ->
+ communalInteractor.ongoingContent(isMediaHostVisible).onEach {
+ mediaHost.updateViewVisibility()
}
}
@@ -148,8 +142,7 @@
ongoingContent,
communalInteractor.widgetContent,
communalInteractor.ctaTileContent,
- ) { ongoing, widgets, ctaTile,
- ->
+ ) { ongoing, widgets, ctaTile ->
ongoing + widgets + ctaTile
}
}
@@ -172,10 +165,10 @@
allOf(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Communal,
- stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB
+ stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB,
),
keyguardInteractor.isKeyguardOccluded,
- not(keyguardInteractor.isAbleToDream)
+ not(keyguardInteractor.isAbleToDream),
)
.distinctUntilChanged()
.onEach { logger.d("isCommunalContentFlowFrozen: $it") }
@@ -208,7 +201,7 @@
combine(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Communal,
- stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB
+ stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB,
),
communalInteractor.isIdleOnCommunal,
shadeInteractor.isAnyFullyExpanded,
@@ -221,7 +214,7 @@
object : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
// Hint user to long press in order to enter edit mode
@@ -230,7 +223,7 @@
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id,
resources
.getString(R.string.accessibility_action_label_edit_widgets)
- .lowercase()
+ .lowercase(),
)
)
}
@@ -238,7 +231,7 @@
override fun performAccessibilityAction(
host: View,
action: Int,
- args: Bundle?
+ args: Bundle?,
): Boolean {
when (action) {
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id -> {
@@ -271,9 +264,7 @@
}
}
- override fun onOpenWidgetEditor(
- shouldOpenWidgetPickerOnStart: Boolean,
- ) {
+ override fun onOpenWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean) {
persistScrollPosition()
communalInteractor.showWidgetEditor(shouldOpenWidgetPickerOnStart)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index 0e39a99..ec03227 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -21,8 +21,10 @@
import android.util.SizeF
import com.android.app.tracing.coroutines.withContext
import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.widgets.AppWidgetHostListenerDelegate
import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import com.android.systemui.communal.widgets.CommunalAppWidgetHostView
+import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.dagger.qualifiers.UiBackground
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -33,6 +35,8 @@
constructor(
@UiBackground private val uiBgContext: CoroutineContext,
private val appWidgetHost: CommunalAppWidgetHost,
+ private val interactionHandler: WidgetInteractionHandler,
+ private val listenerFactory: AppWidgetHostListenerDelegate.Factory,
) {
suspend fun createWidget(
context: Context,
@@ -40,18 +44,20 @@
size: SizeF,
): CommunalAppWidgetHostView =
withContext("$TAG#createWidget", uiBgContext) {
- appWidgetHost
- .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
- .apply {
- updateAppWidgetSize(
- /* newOptions = */ Bundle(),
- /* minWidth = */ size.width.toInt(),
- /* minHeight = */ size.height.toInt(),
- /* maxWidth = */ size.width.toInt(),
- /* maxHeight = */ size.height.toInt(),
- /* ignorePadding = */ true,
- )
- }
+ val view = CommunalAppWidgetHostView(context, interactionHandler)
+ view.setAppWidget(model.appWidgetId, model.providerInfo)
+ // Instead of setting the view as the listener directly, we wrap the view in a delegate
+ // which ensures the callbacks always get called on the main thread.
+ appWidgetHost.setListener(model.appWidgetId, listenerFactory.create(view))
+ view.updateAppWidgetSize(
+ /* newOptions = */ Bundle(),
+ /* minWidth = */ size.width.toInt(),
+ /* minHeight = */ size.height.toInt(),
+ /* maxWidth = */ size.width.toInt(),
+ /* maxHeight = */ size.height.toInt(),
+ /* ignorePadding = */ true,
+ )
+ view
}
private companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt
new file mode 100644
index 0000000..f341621
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.appwidget.AppWidgetHost.AppWidgetHostListener
+import android.appwidget.AppWidgetProviderInfo
+import android.widget.RemoteViews
+import com.android.systemui.dagger.qualifiers.Main
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.concurrent.Executor
+
+/**
+ * Wrapper for an [AppWidgetHostListener] to ensure the callbacks are executed on the main thread.
+ */
+class AppWidgetHostListenerDelegate
+@AssistedInject
+constructor(
+ @Main private val mainExecutor: Executor,
+ @Assisted private val listener: AppWidgetHostListener,
+) : AppWidgetHostListener {
+
+ @AssistedFactory
+ interface Factory {
+ fun create(listener: AppWidgetHostListener): AppWidgetHostListenerDelegate
+ }
+
+ override fun onUpdateProviderInfo(appWidget: AppWidgetProviderInfo?) {
+ mainExecutor.execute { listener.onUpdateProviderInfo(appWidget) }
+ }
+
+ override fun updateAppWidget(views: RemoteViews?) {
+ mainExecutor.execute { listener.updateAppWidget(views) }
+ }
+
+ override fun onViewDataChanged(viewId: Int) {
+ mainExecutor.execute { listener.onViewDataChanged(viewId) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
index 10a565f..b46698e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
@@ -17,11 +17,7 @@
package com.android.systemui.communal.widgets
import android.appwidget.AppWidgetHost
-import android.appwidget.AppWidgetHostView
-import android.appwidget.AppWidgetProviderInfo
import android.content.Context
-import android.os.Looper
-import android.widget.RemoteViews
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import javax.annotation.concurrent.GuardedBy
@@ -36,11 +32,8 @@
context: Context,
private val backgroundScope: CoroutineScope,
hostId: Int,
- private val interactionHandler: RemoteViews.InteractionHandler,
- looper: Looper,
logBuffer: LogBuffer,
-) : AppWidgetHost(context, hostId, interactionHandler, looper) {
-
+) : AppWidgetHost(context, hostId) {
private val logger = Logger(logBuffer, TAG)
private val _appWidgetIdToRemove = MutableSharedFlow<Int>()
@@ -50,29 +43,6 @@
@GuardedBy("observers") private val observers = mutableSetOf<Observer>()
- override fun onCreateView(
- context: Context,
- appWidgetId: Int,
- appWidget: AppWidgetProviderInfo?
- ): AppWidgetHostView {
- return CommunalAppWidgetHostView(context, interactionHandler)
- }
-
- /**
- * Creates and returns a [CommunalAppWidgetHostView]. This method does the same thing as
- * `createView`. The only difference is that the returned value will be casted to
- * [CommunalAppWidgetHostView].
- */
- fun createViewForCommunal(
- context: Context?,
- appWidgetId: Int,
- appWidget: AppWidgetProviderInfo?
- ): CommunalAppWidgetHostView {
- // `createView` internally calls `onCreateView` to create the view. We cannot override
- // `createView`, but we are sure that the hostView is `CommunalAppWidgetHostView`
- return createView(context, appWidgetId, appWidget) as CommunalAppWidgetHostView
- }
-
override fun onAppWidgetRemoved(appWidgetId: Int) {
backgroundScope.launch {
logger.i({ "App widget removed from system: $int1" }) { int1 = appWidgetId }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
index 684303ae..f4962085 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
@@ -20,7 +20,6 @@
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.res.Resources
-import android.os.Looper
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -46,18 +45,9 @@
fun provideCommunalAppWidgetHost(
@Application context: Context,
@Background backgroundScope: CoroutineScope,
- interactionHandler: WidgetInteractionHandler,
- @Main looper: Looper,
@CommunalLog logBuffer: LogBuffer,
): CommunalAppWidgetHost {
- return CommunalAppWidgetHost(
- context,
- backgroundScope,
- APP_WIDGET_HOST_ID,
- interactionHandler,
- looper,
- logBuffer,
- )
+ return CommunalAppWidgetHost(context, backgroundScope, APP_WIDGET_HOST_ID, logBuffer)
}
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index d84dc20..13b4aa9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -50,6 +50,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import javax.inject.Inject
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@@ -244,15 +245,18 @@
private fun listenForTransitionAndChangeScene() {
lifecycleScope.launch {
communalViewModel.canShowEditMode.collect {
- communalViewModel.changeScene(
- scene = CommunalScenes.Blank,
- loggingReason = "edit mode opening",
- transitionKey = CommunalTransitionKeys.ToEditMode,
- keyguardState = KeyguardState.GONE,
- )
- // wait till transitioned to Blank scene, then animate in communal content in
- // edit mode
- communalViewModel.currentScene.first { it == CommunalScenes.Blank }
+ if (!SceneContainerFlag.isEnabled) {
+ communalViewModel.changeScene(
+ scene = CommunalScenes.Blank,
+ loggingReason = "edit mode opening",
+ transitionKey = CommunalTransitionKeys.ToEditMode,
+ keyguardState = KeyguardState.GONE,
+ )
+ // wait till transitioned to Blank scene, then animate in communal content in
+ // edit mode
+ communalViewModel.currentScene.first { it == CommunalScenes.Blank }
+ }
+
communalViewModel.setEditModeState(EditModeState.SHOWING)
// Inform the ActivityController that we are now fully visible.
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 7018f9d..dbd7f07 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -24,8 +24,11 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -34,6 +37,7 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -59,6 +63,7 @@
private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
private val dismissCallbackRegistry: DismissCallbackRegistry,
+ sceneBackInteractor: SceneBackInteractor,
) {
/**
* Whether the device is unlocked.
@@ -86,19 +91,40 @@
* Note: This does not imply that the lockscreen is visible or not.
*/
val isDeviceEntered: StateFlow<Boolean> =
- sceneInteractor.currentScene
- .filter { currentScene ->
- currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
- }
- .mapLatestConflated { scene ->
- if (scene == Scenes.Gone) {
- // Make sure device unlock status is definitely unlocked before we consider the
- // device "entered".
- deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
- true
- } else {
- false
- }
+ combine(
+ // This flow emits true when the currentScene switches to Gone for the first time
+ // after having been on Lockscreen.
+ sceneInteractor.currentScene
+ .filter { currentScene ->
+ currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
+ }
+ .mapLatestConflated { scene ->
+ if (scene == Scenes.Gone) {
+ // Make sure device unlock status is definitely unlocked before we
+ // consider the device "entered".
+ deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
+ true
+ } else {
+ false
+ }
+ },
+ // This flow emits true only if the bottom of the navigation back stack has been
+ // switched from Lockscreen to Gone. In other words, only if the device was unlocked
+ // while visiting at least one scene "above" the Lockscreen scene.
+ sceneBackInteractor.backStack
+ // The bottom of the back stack, which is Lockscreen, Gone, or null if empty.
+ .map { it.asIterable().lastOrNull() }
+ // Filter out cases where the stack changes but the bottom remains unchanged.
+ .distinctUntilChanged()
+ // Detect changes of the bottom of the stack, start with null, so the first
+ // update emits a value and the logic doesn't need to wait for a second value
+ // before emitting something.
+ .pairwise(initialValue = null)
+ // Replacing a bottom of the stack that was Lockscreen with Gone constitutes a
+ // "device entered" event.
+ .map { (from, to) -> from == Scenes.Lockscreen && to == Scenes.Gone },
+ ) { enteredDirectly, enteredOnBackStack ->
+ enteredOnBackStack || enteredDirectly
}
.stateIn(
scope = applicationScope,
@@ -129,7 +155,7 @@
},
isLockscreenEnabled,
deviceUnlockedInteractor.deviceUnlockStatus,
- isDeviceEntered
+ isDeviceEntered,
) { isNoneAuthMethod, isLockscreenEnabled, deviceUnlockStatus, isDeviceEntered ->
val isSwipeAuthMethod = isNoneAuthMethod && isLockscreenEnabled
(isSwipeAuthMethod ||
@@ -155,9 +181,7 @@
* canceled
*/
@JvmOverloads
- fun attemptDeviceEntry(
- callback: IKeyguardDismissCallback? = null,
- ) {
+ fun attemptDeviceEntry(callback: IKeyguardDismissCallback? = null) {
callback?.let { dismissCallbackRegistry.addCallback(it) }
// TODO (b/307768356),
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 1f5878b..a327e4a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -28,7 +28,6 @@
import android.view.Display
import com.android.app.tracing.FlowTracing.traceEach
import com.android.app.tracing.traceSection
-import com.android.systemui.Flags
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -51,7 +50,6 @@
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.scan
-import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
/** Provides a [Flow] of [Display] as returned by [DisplayManager]. */
@@ -102,7 +100,7 @@
private val displayManager: DisplayManager,
@Background backgroundHandler: Handler,
@Background bgApplicationScope: CoroutineScope,
- @Background backgroundCoroutineDispatcher: CoroutineDispatcher
+ @Background backgroundCoroutineDispatcher: CoroutineDispatcher,
) : DisplayRepository {
private val allDisplayEvents: Flow<DisplayEvent> =
conflatedCallbackFlow {
@@ -139,70 +137,55 @@
override val displayAdditionEvent: Flow<Display?> =
allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map { getDisplay(it.displayId) }
- // TODO: b/345472038 - Delete after the flag is ramped up.
- private val oldEnabledDisplays: Flow<Set<Display>> =
- allDisplayEvents
- .map { getDisplays() }
- .shareIn(bgApplicationScope, started = SharingStarted.WhileSubscribed(), replay = 1)
+ // This is necessary because there might be multiple displays, and we could
+ // have missed events for those added before this process or flow started.
+ // Note it causes a binder call from the main thread (it's traced).
+ private val initialDisplays: Set<Display> =
+ traceSection("$TAG#initialDisplays") { displayManager.displays?.toSet() ?: emptySet() }
+ private val initialDisplayIds = initialDisplays.map { display -> display.displayId }.toSet()
/** Propagate to the listeners only enabled displays */
private val enabledDisplayIds: Flow<Set<Int>> =
- if (Flags.enableEfficientDisplayRepository()) {
- allDisplayEvents
- .scan(initial = emptySet()) { previousIds: Set<Int>, event: DisplayEvent ->
- val id = event.displayId
- when (event) {
- is DisplayEvent.Removed -> previousIds - id
- is DisplayEvent.Added,
- is DisplayEvent.Changed -> previousIds + id
- }
- }
- .distinctUntilChanged()
- .stateIn(
- bgApplicationScope,
- SharingStarted.WhileSubscribed(),
- // This is necessary because there might be multiple displays, and we could
- // have missed events for those added before this process or flow started.
- // Note it causes a binder call from the main thread (it's traced).
- getDisplays().map { display -> display.displayId }.toSet(),
- )
- } else {
- oldEnabledDisplays.map { enabledDisplaysSet ->
- enabledDisplaysSet.map { it.displayId }.toSet()
+ allDisplayEvents
+ .scan(initial = initialDisplayIds) { previousIds: Set<Int>, event: DisplayEvent ->
+ val id = event.displayId
+ when (event) {
+ is DisplayEvent.Removed -> previousIds - id
+ is DisplayEvent.Added,
+ is DisplayEvent.Changed -> previousIds + id
}
}
+ .distinctUntilChanged()
+ .stateIn(bgApplicationScope, SharingStarted.WhileSubscribed(), initialDisplayIds)
.debugLog("enabledDisplayIds")
private val defaultDisplay by lazy {
getDisplay(Display.DEFAULT_DISPLAY) ?: error("Unable to get default display.")
}
+
/**
* Represents displays that went though the [DisplayListener.onDisplayAdded] callback.
*
* Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
*/
private val enabledDisplays: Flow<Set<Display>> =
- if (Flags.enableEfficientDisplayRepository()) {
- enabledDisplayIds
- .mapElementsLazily { displayId -> getDisplay(displayId) }
- .onEach {
- if (it.isEmpty()) Log.wtf(TAG, "No enabled displays. This should never happen.")
- }
- .flowOn(backgroundCoroutineDispatcher)
- .debugLog("enabledDisplays")
- .stateIn(
- bgApplicationScope,
- started = SharingStarted.WhileSubscribed(),
- // This triggers a single binder call on the UI thread per process. The
- // alternative would be to use sharedFlows, but they are prohibited due to
- // performance concerns.
- // Ultimately, this is a trade-off between a one-time UI thread binder call and
- // the constant overhead of sharedFlows.
- initialValue = getDisplays()
- )
- } else {
- oldEnabledDisplays
- }
+ enabledDisplayIds
+ .mapElementsLazily { displayId -> getDisplay(displayId) }
+ .onEach {
+ if (it.isEmpty()) Log.wtf(TAG, "No enabled displays. This should never happen.")
+ }
+ .flowOn(backgroundCoroutineDispatcher)
+ .debugLog("enabledDisplays")
+ .stateIn(
+ bgApplicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ // This triggers a single binder call on the UI thread per process. The
+ // alternative would be to use sharedFlows, but they are prohibited due to
+ // performance concerns.
+ // Ultimately, this is a trade-off between a one-time UI thread binder call and
+ // the constant overhead of sharedFlows.
+ initialValue = initialDisplays,
+ )
/**
* Represents displays that went though the [DisplayListener.onDisplayAdded] callback.
@@ -211,10 +194,7 @@
*/
override val displays: Flow<Set<Display>> = enabledDisplays
- private fun getDisplays(): Set<Display> =
- traceSection("$TAG#getDisplays()") { displayManager.displays?.toSet() ?: emptySet() }
-
- private val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
+ val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
private val ignoredDisplayIds: Flow<Set<Int>> = _ignoredDisplayIds.debugLog("ignoredDisplayIds")
private fun getInitialConnectedDisplays(): Set<Int> =
@@ -271,7 +251,7 @@
// the flow starts being collected. This is to ensure the call to get displays (an
// IPC) happens in the background instead of when this object
// is instantiated.
- initialValue = emptySet()
+ initialValue = emptySet(),
)
private val connectedExternalDisplayIds: Flow<Set<Int>> =
@@ -308,7 +288,7 @@
TAG,
"combining enabled=$enabledDisplaysIds, " +
"connectedExternalDisplayIds=$connectedExternalDisplayIds, " +
- "ignored=$ignoredDisplayIds"
+ "ignored=$ignoredDisplayIds",
)
}
connectedExternalDisplayIds - enabledDisplaysIds - ignoredDisplayIds
@@ -382,7 +362,7 @@
val previousSet: Set<T>,
// Caches T values from the previousSet that were already converted to V
val valueMap: Map<T, V>,
- val resultSet: Set<V>
+ val resultSet: Set<V>,
)
val emptyInitialState = State(emptySet<T>(), emptyMap(), emptySet<V>())
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index dcca12f..11a0543 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -144,7 +144,7 @@
useSinglePane,
onSearchQueryChanged,
modifier,
- onKeyboardSettingsClicked
+ onKeyboardSettingsClicked,
)
}
else -> {
@@ -159,7 +159,7 @@
useSinglePane: @Composable () -> Boolean,
onSearchQueryChanged: (String) -> Unit,
modifier: Modifier,
- onKeyboardSettingsClicked: () -> Unit
+ onKeyboardSettingsClicked: () -> Unit,
) {
var selectedCategoryType by
remember(shortcutsUiState.defaultSelectedCategory) {
@@ -183,7 +183,7 @@
shortcutsUiState.shortcutCategories,
selectedCategoryType,
onCategorySelected = { selectedCategoryType = it },
- onKeyboardSettingsClicked
+ onKeyboardSettingsClicked,
)
}
}
@@ -223,14 +223,14 @@
searchQuery,
categories,
selectedCategoryType,
- onCategorySelected
+ onCategorySelected,
)
Spacer(modifier = Modifier.weight(1f))
}
KeyboardSettings(
horizontalPadding = 16.dp,
verticalPadding = 32.dp,
- onClick = onKeyboardSettingsClicked
+ onClick = onKeyboardSettingsClicked,
)
}
}
@@ -282,11 +282,7 @@
onClick: () -> Unit,
shape: Shape,
) {
- Surface(
- color = MaterialTheme.colorScheme.surfaceBright,
- shape = shape,
- onClick = onClick,
- ) {
+ Surface(color = MaterialTheme.colorScheme.surfaceBright, shape = shape, onClick = onClick) {
Column {
Row(
verticalAlignment = Alignment.CenterVertically,
@@ -327,7 +323,7 @@
source: IconSource,
modifier: Modifier = Modifier,
contentDescription: String? = null,
- tint: Color = LocalContentColor.current
+ tint: Color = LocalContentColor.current,
) {
if (source.imageVector != null) {
Icon(source.imageVector, contentDescription, modifier, tint)
@@ -350,7 +346,7 @@
private fun getApplicationLabelForCurrentApp(
type: ShortcutCategoryType.CurrentApp,
- context: Context
+ context: Context,
): String {
val packageManagerForUser = CentralSurfaces.getPackageManagerForUser(context, context.userId)
return try {
@@ -358,7 +354,7 @@
packageManagerForUser.getApplicationInfoAsUser(
type.packageName,
/* flags = */ 0,
- context.userId
+ context.userId,
)
packageManagerForUser.getApplicationLabel(currentAppInfo).toString()
} catch (e: NameNotFoundException) {
@@ -377,13 +373,13 @@
} else {
0f
},
- label = "Expand icon rotation animation"
+ label = "Expand icon rotation animation",
)
Icon(
modifier =
Modifier.background(
color = MaterialTheme.colorScheme.surfaceContainerHigh,
- shape = CircleShape
+ shape = CircleShape,
)
.graphicsLayer { rotationZ = expandIconRotationDegrees },
imageVector = Icons.Default.ExpandMore,
@@ -393,7 +389,7 @@
} else {
stringResource(R.string.shortcut_helper_content_description_expand_icon)
},
- tint = MaterialTheme.colorScheme.onSurface
+ tint = MaterialTheme.colorScheme.onSurface,
)
}
@@ -435,11 +431,11 @@
Row(Modifier.fillMaxWidth()) {
StartSidePanel(
onSearchQueryChanged = onSearchQueryChanged,
- modifier = Modifier.width(200.dp),
+ modifier = Modifier.width(240.dp),
categories = categories,
onKeyboardSettingsClicked = onKeyboardSettingsClicked,
selectedCategory = selectedCategoryType,
- onCategoryClicked = { onCategorySelected(it.type) }
+ onCategoryClicked = { onCategorySelected(it.type) },
)
Spacer(modifier = Modifier.width(24.dp))
EndSidePanel(searchQuery, Modifier.fillMaxSize().padding(top = 8.dp), selectedCategory)
@@ -475,7 +471,7 @@
modifier
.padding(vertical = 8.dp)
.background(MaterialTheme.colorScheme.surfaceBright, RoundedCornerShape(28.dp))
- .padding(horizontal = horizontalPadding, vertical = 24.dp)
+ .padding(horizontal = horizontalPadding, vertical = 24.dp),
)
}
@@ -484,7 +480,7 @@
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(28.dp),
- color = MaterialTheme.colorScheme.surfaceBright
+ color = MaterialTheme.colorScheme.surfaceBright,
) {
Column(Modifier.padding(24.dp)) {
SubCategoryTitle(subCategory.label)
@@ -519,7 +515,7 @@
isFocused = isFocused,
focusColor = MaterialTheme.colorScheme.secondary,
padding = 8.dp,
- cornerRadius = 16.dp
+ cornerRadius = 16.dp,
)
) {
Row(
@@ -528,21 +524,12 @@
verticalAlignment = Alignment.CenterVertically,
) {
if (shortcut.icon != null) {
- ShortcutIcon(
- shortcut.icon,
- modifier = Modifier.size(24.dp),
- )
+ ShortcutIcon(shortcut.icon, modifier = Modifier.size(24.dp))
}
- ShortcutDescriptionText(
- searchQuery = searchQuery,
- shortcut = shortcut,
- )
+ ShortcutDescriptionText(searchQuery = searchQuery, shortcut = shortcut)
}
Spacer(modifier = Modifier.width(16.dp))
- ShortcutKeyCombinations(
- modifier = Modifier.weight(1f),
- shortcut = shortcut,
- )
+ ShortcutKeyCombinations(modifier = Modifier.weight(1f), shortcut = shortcut)
}
}
@@ -566,14 +553,11 @@
@OptIn(ExperimentalLayoutApi::class)
@Composable
-private fun ShortcutKeyCombinations(
- modifier: Modifier = Modifier,
- shortcut: Shortcut,
-) {
+private fun ShortcutKeyCombinations(modifier: Modifier = Modifier, shortcut: Shortcut) {
FlowRow(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
- horizontalArrangement = Arrangement.End
+ horizontalArrangement = Arrangement.End,
) {
shortcut.commands.forEachIndexed { index, command ->
if (index > 0) {
@@ -609,8 +593,8 @@
Modifier.height(36.dp)
.background(
color = MaterialTheme.colorScheme.surfaceContainer,
- shape = RoundedCornerShape(12.dp)
- ),
+ shape = RoundedCornerShape(12.dp),
+ )
) {
shortcutKeyContent()
}
@@ -630,7 +614,7 @@
Icon(
painter = painterResource(key.drawableResId),
contentDescription = null,
- modifier = Modifier.align(Alignment.Center).padding(6.dp)
+ modifier = Modifier.align(Alignment.Center).padding(6.dp),
)
}
@@ -701,7 +685,7 @@
KeyboardSettings(
horizontalPadding = 24.dp,
verticalPadding = 24.dp,
- onKeyboardSettingsClicked
+ onKeyboardSettingsClicked,
)
}
}
@@ -710,7 +694,7 @@
private fun CategoriesPanelTwoPane(
categories: List<ShortcutCategory>,
selectedCategory: ShortcutCategoryType?,
- onCategoryClicked: (ShortcutCategory) -> Unit
+ onCategoryClicked: (ShortcutCategory) -> Unit,
) {
Column {
categories.fastForEach {
@@ -718,7 +702,7 @@
label = it.label(LocalContext.current),
iconSource = it.icon,
selected = selectedCategory == it.type,
- onClick = { onCategoryClicked(it) }
+ onClick = { onCategoryClicked(it) },
)
}
}
@@ -736,29 +720,29 @@
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
- Surface(
+ SelectableShortcutSurface(
selected = selected,
onClick = onClick,
modifier =
Modifier.semantics { role = Role.Tab }
.heightIn(min = 64.dp)
.fillMaxWidth()
- .focusable(interactionSource = interactionSource)
.outlineFocusModifier(
isFocused = isFocused,
focusColor = MaterialTheme.colorScheme.secondary,
padding = 2.dp,
- cornerRadius = 33.dp
+ cornerRadius = 33.dp,
),
shape = RoundedCornerShape(28.dp),
color = colors.containerColor(selected).value,
+ interactionSource = interactionSource
) {
Row(Modifier.padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) {
ShortcutCategoryIcon(
modifier = Modifier.size(24.dp),
source = iconSource,
contentDescription = null,
- tint = colors.iconColor(selected).value
+ tint = colors.iconColor(selected).value,
)
Spacer(Modifier.width(12.dp))
Box(Modifier.weight(1f)) {
@@ -766,7 +750,7 @@
fontSize = 18.sp,
color = colors.textColor(selected).value,
style = MaterialTheme.typography.headlineSmall,
- text = label
+ text = label,
)
}
}
@@ -777,7 +761,7 @@
isFocused: Boolean,
focusColor: Color,
padding: Dp,
- cornerRadius: Dp
+ cornerRadius: Dp,
): Modifier {
if (isFocused) {
return this.drawWithContent {
@@ -795,7 +779,7 @@
style = Stroke(width = 3.dp.toPx()),
topLeft = focusOutline.topLeft,
size = focusOutline.size,
- cornerRadius = CornerRadius(cornerRadius.toPx())
+ cornerRadius = CornerRadius(cornerRadius.toPx()),
)
}
// Increasing Z-Index so focus outline is drawn on top of "selected" category
@@ -815,9 +799,9 @@
Text(
text = stringResource(R.string.shortcut_helper_title),
color = MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.headlineSmall
+ style = MaterialTheme.typography.headlineSmall,
)
- }
+ },
)
}
@@ -852,7 +836,7 @@
onSearch = {},
leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) },
placeholder = { Text(text = stringResource(R.string.shortcut_helper_search_placeholder)) },
- content = {}
+ content = {},
)
}
@@ -860,14 +844,12 @@
private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick: () -> Unit) {
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
- Surface(
+ ClickableShortcutSurface(
onClick = onClick,
shape = RoundedCornerShape(24.dp),
color = Color.Transparent,
- modifier =
- Modifier.semantics { role = Role.Button }
- .fillMaxWidth()
- .focusable(interactionSource = interactionSource)
+ modifier = Modifier.semantics { role = Role.Button }.fillMaxWidth(),
+ interactionSource = interactionSource
) {
Row(
modifier =
@@ -876,21 +858,21 @@
isFocused = isFocused,
focusColor = MaterialTheme.colorScheme.secondary,
padding = 8.dp,
- cornerRadius = 28.dp
+ cornerRadius = 28.dp,
),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
Text(
"Keyboard Settings",
color = MaterialTheme.colorScheme.onSurfaceVariant,
- fontSize = 16.sp
+ fontSize = 16.sp,
)
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.AutoMirrored.Default.OpenInNew,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.size(24.dp)
+ modifier = Modifier.size(24.dp),
)
}
}
@@ -902,17 +884,15 @@
val singlePaneFirstCategory =
RoundedCornerShape(
topStart = Dimensions.SinglePaneCategoryCornerRadius,
- topEnd = Dimensions.SinglePaneCategoryCornerRadius
+ topEnd = Dimensions.SinglePaneCategoryCornerRadius,
)
val singlePaneLastCategory =
RoundedCornerShape(
bottomStart = Dimensions.SinglePaneCategoryCornerRadius,
- bottomEnd = Dimensions.SinglePaneCategoryCornerRadius
+ bottomEnd = Dimensions.SinglePaneCategoryCornerRadius,
)
val singlePaneSingleCategory =
- RoundedCornerShape(
- size = Dimensions.SinglePaneCategoryCornerRadius,
- )
+ RoundedCornerShape(size = Dimensions.SinglePaneCategoryCornerRadius)
val singlePaneCategory = RectangleShape
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
new file mode 100644
index 0000000..3ba3bd8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui.composable
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.LocalAbsoluteTonalElevation
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.LocalTonalElevationEnabled
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.contentColorFor
+import androidx.compose.material3.minimumInteractiveComponentSize
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.NonRestartableComposable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.android.compose.modifiers.thenIf
+
+/**
+ * A selectable surface with no default focus/hover indications.
+ *
+ * This composable is similar to [androidx.compose.material3.Surface], but removes default
+ * focus/hover states to enable custom implementations.
+ */
+@Composable
+@NonRestartableComposable
+fun SelectableShortcutSurface(
+ selected: Boolean,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shape: Shape = RectangleShape,
+ color: Color = MaterialTheme.colorScheme.surface,
+ contentColor: Color = contentColorFor(color),
+ tonalElevation: Dp = 0.dp,
+ shadowElevation: Dp = 0.dp,
+ border: BorderStroke? = null,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable () -> Unit
+) {
+ @Suppress("NAME_SHADOWING")
+ val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
+ val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor,
+ LocalAbsoluteTonalElevation provides absoluteElevation
+ ) {
+ Box(
+ modifier =
+ modifier
+ .minimumInteractiveComponentSize()
+ .surface(
+ shape = shape,
+ backgroundColor =
+ surfaceColorAtElevation(color = color, elevation = absoluteElevation),
+ border = border,
+ shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() }
+ )
+ .selectable(
+ selected = selected,
+ interactionSource = interactionSource,
+ indication = null,
+ enabled = enabled,
+ onClick = onClick
+ ),
+ propagateMinConstraints = true
+ ) {
+ content()
+ }
+ }
+}
+
+/**
+ * A clickable surface with no default focus/hover indications.
+ *
+ * This composable is similar to [androidx.compose.material3.Surface], but removes default
+ * focus/hover states to enable custom implementations.
+ */
+@Composable
+@NonRestartableComposable
+fun ClickableShortcutSurface(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shape: Shape = RectangleShape,
+ color: Color = MaterialTheme.colorScheme.surface,
+ contentColor: Color = contentColorFor(color),
+ tonalElevation: Dp = 0.dp,
+ shadowElevation: Dp = 0.dp,
+ border: BorderStroke? = null,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable () -> Unit
+) {
+ @Suppress("NAME_SHADOWING")
+ val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
+ val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor,
+ LocalAbsoluteTonalElevation provides absoluteElevation
+ ) {
+ Box(
+ modifier =
+ modifier
+ .minimumInteractiveComponentSize()
+ .surface(
+ shape = shape,
+ backgroundColor =
+ surfaceColorAtElevation(color = color, elevation = absoluteElevation),
+ border = border,
+ shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() }
+ )
+ .clickable(
+ interactionSource = interactionSource,
+ indication = null,
+ enabled = enabled,
+ onClick = onClick
+ ),
+ propagateMinConstraints = true
+ ) {
+ content()
+ }
+ }
+}
+
+@Composable
+private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color {
+ return MaterialTheme.colorScheme.applyTonalElevation(color, elevation)
+}
+
+@Composable
+internal fun ColorScheme.applyTonalElevation(backgroundColor: Color, elevation: Dp): Color {
+ val tonalElevationEnabled = LocalTonalElevationEnabled.current
+ return if (backgroundColor == surface && tonalElevationEnabled) {
+ surfaceColorAtElevation(elevation)
+ } else {
+ backgroundColor
+ }
+}
+
+/**
+ * Applies surface-related modifiers to a composable.
+ *
+ * This function adds background, border, and shadow effects to a composable. Also ensure the
+ * composable is clipped to the given shape.
+ *
+ * @param shape The shape to apply to the composable's background, border, and clipping.
+ * @param backgroundColor The background color to apply to the composable.
+ * @param border An optional border to draw around the composable.
+ * @param shadowElevation The size of the shadow below the surface. To prevent shadow creep, only
+ * apply shadow elevation when absolutely necessary, such as when the surface requires visual
+ * separation from a patterned background. Note that It will not affect z index of the Surface. If
+ * you want to change the drawing order you can use `Modifier.zIndex`.
+ * @return The modified Modifier instance with surface-related modifiers applied.
+ */
+@Stable
+private fun Modifier.surface(
+ shape: Shape,
+ backgroundColor: Color,
+ border: BorderStroke?,
+ shadowElevation: Float,
+): Modifier {
+ return this.thenIf(shadowElevation > 0f) {
+ Modifier.graphicsLayer(shadowElevation = shadowElevation, shape = shape, clip = false)
+ }
+ .thenIf(border != null) { Modifier.border(border!!, shape) }
+ .background(color = backgroundColor, shape = shape)
+ .clip(shape)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
index 2039743..799999a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
@@ -39,6 +39,7 @@
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.dpToPx
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
@@ -51,10 +52,8 @@
*/
class ShortcutHelperActivity
@Inject
-constructor(
- private val userTracker: UserTracker,
- private val viewModel: ShortcutHelperViewModel,
-) : ComponentActivity() {
+constructor(private val userTracker: UserTracker, private val viewModel: ShortcutHelperViewModel) :
+ ComponentActivity() {
private val bottomSheetContainer
get() = requireViewById<View>(R.id.shortcut_helper_sheet_container)
@@ -69,7 +68,7 @@
setupEdgeToEdge()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_keyboard_shortcut_helper)
- setUpBottomSheetWidth()
+ setUpWidth()
expandBottomSheet()
setUpInsets()
setUpPredictiveBack()
@@ -80,6 +79,13 @@
viewModel.onViewOpened()
}
+ private fun setUpWidth() {
+ // we override this because when maxWidth isn't specified, material imposes a max width
+ // constraint on bottom sheets on larger screens which is smaller than our desired width.
+ bottomSheetBehavior.maxWidth =
+ resources.getDimension(R.dimen.shortcut_helper_width).dpToPx(resources).toInt()
+ }
+
private fun setUpComposeView() {
requireViewById<ComposeView>(R.id.shortcut_helper_compose_container).apply {
setContent {
@@ -102,7 +108,7 @@
try {
startActivityAsUser(
Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS),
- userTracker.userHandle
+ userTracker.userHandle,
)
} catch (e: ActivityNotFoundException) {
// From the Settings docs: In some cases, a matching Activity may not exist, so ensure
@@ -133,15 +139,6 @@
window.setDecorFitsSystemWindows(false)
}
- private fun setUpBottomSheetWidth() {
- val sheetScreenWidthFraction =
- resources.getFloat(R.dimen.shortcut_helper_screen_width_fraction)
- // maxWidth needs to be set before the sheet is drawn, otherwise the call will have no
- // effect.
- val screenWidth = windowManager.maximumWindowMetrics.bounds.width()
- bottomSheetBehavior.maxWidth = (sheetScreenWidthFraction * screenWidth).toInt()
- }
-
private fun setUpInsets() {
bottomSheetContainer.setOnApplyWindowInsetsListener { _, insets ->
val safeDrawingInsets = insets.safeDrawing
@@ -153,7 +150,7 @@
bottomSheet.updatePadding(
left = safeDrawingInsets.left,
right = safeDrawingInsets.right,
- bottom = safeDrawingInsets.bottom
+ bottom = safeDrawingInsets.bottom,
)
// The bottom sheet has to be expanded only after setting up insets, otherwise there is
// a bug and it will not use full height.
@@ -191,7 +188,7 @@
}
onBackPressedDispatcher.addCallback(
owner = this,
- onBackPressedCallback = onBackPressedCallback
+ onBackPressedCallback = onBackPressedCallback,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 228e01e..cd5daf9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -108,7 +108,7 @@
.transition(
edge = Edge.create(from = KeyguardState.LOCKSCREEN, to = Scenes.Gone),
edgeWithoutSceneContainer =
- Edge.create(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ Edge.create(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE),
)
.map<TransitionStep, Boolean?> {
true // Make the surface visible during LS -> GONE transitions.
@@ -162,7 +162,7 @@
.collect {
startTransitionTo(
KeyguardState.PRIMARY_BOUNCER,
- ownerReason = "#listenForLockscreenToPrimaryBouncer"
+ ownerReason = "#listenForLockscreenToPrimaryBouncer",
)
}
}
@@ -238,7 +238,7 @@
getDefaultAnimatorForTransitionsToState(
KeyguardState.LOCKSCREEN
)
- .apply { duration = 0 }
+ .apply { duration = 0 },
)
)
}
@@ -249,6 +249,8 @@
if (
// Use currentTransitionInfo to decide whether to start the transition.
currentTransitionInfo.to == KeyguardState.LOCKSCREEN &&
+ shadeExpansion > 0f &&
+ shadeExpansion < 1f &&
shadeRepository.legacyShadeTracking.value &&
!isKeyguardUnlocked &&
statusBarState == KEYGUARD
@@ -257,7 +259,7 @@
startTransitionTo(
toState = KeyguardState.PRIMARY_BOUNCER,
animator = null, // transition will be manually controlled,
- ownerReason = "#listenForLockscreenToPrimaryBouncerDragging"
+ ownerReason = "#listenForLockscreenToPrimaryBouncerDragging",
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index 60c5386..eb9b07a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -21,7 +21,7 @@
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.KeyguardDone
@@ -29,13 +29,12 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolver
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -61,14 +60,11 @@
transitionInteractor: KeyguardTransitionInteractor,
val dismissInteractor: KeyguardDismissInteractor,
@Application private val applicationScope: CoroutineScope,
- sceneInteractor: dagger.Lazy<SceneInteractor>,
- deviceEntryInteractor: dagger.Lazy<DeviceEntryInteractor>,
- quickSettingsSceneFamilyResolver: dagger.Lazy<QuickSettingsSceneFamilyResolver>,
- notifShadeSceneFamilyResolver: dagger.Lazy<NotifShadeSceneFamilyResolver>,
+ sceneInteractor: Lazy<SceneInteractor>,
+ deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
powerInteractor: PowerInteractor,
alternateBouncerInteractor: AlternateBouncerInteractor,
- keyguardInteractor: dagger.Lazy<KeyguardInteractor>,
- shadeInteractor: dagger.Lazy<ShadeInteractor>,
+ shadeInteractor: Lazy<ShadeInteractor>,
) {
val dismissAction: Flow<DismissAction> = repository.dismissAction
@@ -106,18 +102,18 @@
if (SceneContainerFlag.isEnabled) {
combine(
sceneInteractor.get().currentScene,
- deviceEntryInteractor.get().isUnlocked,
- ) { scene, isUnlocked ->
- isUnlocked &&
- (quickSettingsSceneFamilyResolver.get().includesScene(scene) ||
- notifShadeSceneFamilyResolver.get().includesScene(scene))
+ deviceUnlockedInteractor.get().deviceUnlockStatus,
+ ) { scene, unlockStatus ->
+ unlockStatus.isUnlocked &&
+ (scene == Scenes.QuickSettings || scene == Scenes.Shade)
}
.distinctUntilChanged()
} else if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
- shadeInteractor.get().isAnyExpanded.sample(
- keyguardInteractor.get().isKeyguardDismissible
- ) { isAnyExpanded, isKeyguardDismissible ->
- isAnyExpanded && isKeyguardDismissible
+ combine(
+ shadeInteractor.get().isAnyExpanded,
+ deviceUnlockedInteractor.get().deviceUnlockStatus,
+ ) { isAnyExpanded, deviceUnlockStatus ->
+ isAnyExpanded && deviceUnlockStatus.isUnlocked
}
} else {
flow {
@@ -132,7 +128,7 @@
merge(
finishedTransitionToGone,
isOnShadeWhileUnlocked.filter { it }.map {},
- dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction
+ dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction,
)
.sample(dismissAction)
.filterNot { it is DismissAction.None }
@@ -142,11 +138,11 @@
combine(
transitionInteractor.isFinishedIn(
scene = Scenes.Gone,
- stateWithoutSceneContainer = GONE
+ stateWithoutSceneContainer = GONE,
),
transitionInteractor.isFinishedIn(
scene = Scenes.Bouncer,
- stateWithoutSceneContainer = PRIMARY_BOUNCER
+ stateWithoutSceneContainer = PRIMARY_BOUNCER,
),
alternateBouncerInteractor.isVisible,
isOnShadeWhileUnlocked,
@@ -164,7 +160,7 @@
}
fun runAfterKeyguardGone(runnable: Runnable) {
- if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+ if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
setDismissAction(
DismissAction.RunAfterKeyguardGone(
dismissAction = { runnable.run() },
@@ -176,18 +172,18 @@
}
fun setDismissAction(dismissAction: DismissAction) {
- if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+ if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
repository.dismissAction.value.onCancelAction.run()
repository.setDismissAction(dismissAction)
}
fun handleDismissAction() {
- if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+ if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
repository.setDismissAction(DismissAction.None)
}
suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) {
- if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+ if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
dismissInteractor.setKeyguardDone(keyguardDoneTiming)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
index 44aafab..ad1a32e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
@@ -76,7 +76,7 @@
.filter { enabled -> !enabled }
.sampleCombine(
internalTransitionInteractor.currentTransitionInfoInternal,
- biometricSettingsRepository.isCurrentUserInLockdown
+ biometricSettingsRepository.isCurrentUserInLockdown,
)
.map { (_, transitionInfo, inLockdown) ->
// ...we hide the keyguard, if it's showing and we're not in lockdown. In that case,
@@ -91,12 +91,18 @@
*/
scope.launch {
if (!SceneContainerFlag.isEnabled) {
- showKeyguardWhenReenabled
- .filter { shouldDismiss -> shouldDismiss }
- .collect {
- keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
- "keyguard disabled"
- )
+ repository.isKeyguardEnabled
+ .filter { enabled -> !enabled }
+ .sampleCombine(
+ biometricSettingsRepository.isCurrentUserInLockdown,
+ internalTransitionInteractor.currentTransitionInfoInternal,
+ )
+ .collect { (_, inLockdown, currentTransitionInfo) ->
+ if (currentTransitionInfo.to != KeyguardState.GONE && !inLockdown) {
+ keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
+ "keyguard disabled"
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
index 420fbd4..7fd348b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
@@ -20,6 +20,7 @@
import android.os.RemoteException
import com.android.internal.policy.IKeyguardStateCallback
import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -27,13 +28,13 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import javax.inject.Inject
/**
* Updates KeyguardStateCallbacks provided to KeyguardService with KeyguardTransitionInteractor
@@ -50,6 +51,8 @@
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val selectedUserInteractor: SelectedUserInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val trustInteractor: TrustInteractor,
+ private val simBouncerInteractor: SimBouncerInteractor,
) : CoreStartable {
private val callbacks = mutableListOf<IKeyguardStateCallback>()
@@ -60,21 +63,19 @@
applicationScope.launch {
combine(
- selectedUserInteractor.selectedUser,
- keyguardTransitionInteractor.currentKeyguardState,
- ::Pair
- ).collectLatest { (selectedUser, currentState) ->
- val iterator = callbacks.iterator()
+ selectedUserInteractor.selectedUser,
+ keyguardTransitionInteractor.currentKeyguardState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ ::Triple,
+ )
+ .collectLatest { (selectedUser, _, _) ->
+ val iterator = callbacks.iterator()
withContext(backgroundDispatcher) {
while (iterator.hasNext()) {
val callback = iterator.next()
try {
- callback.onShowingStateChanged(
- currentState != KeyguardState.GONE,
- selectedUser
- )
- callback.onInputRestrictedStateChanged(
- currentState != KeyguardState.GONE)
+ callback.onShowingStateChanged(!isIdleInGone(), selectedUser)
+ callback.onInputRestrictedStateChanged(!isIdleInGone())
} catch (e: RemoteException) {
if (e is DeadObjectException) {
iterator.remove()
@@ -84,10 +85,58 @@
}
}
}
+
+ applicationScope.launch {
+ trustInteractor.isTrusted.collectLatest { isTrusted ->
+ val iterator = callbacks.iterator()
+ withContext(backgroundDispatcher) {
+ while (iterator.hasNext()) {
+ val callback = iterator.next()
+ try {
+ callback.onTrustedChanged(isTrusted)
+ } catch (e: RemoteException) {
+ if (e is DeadObjectException) {
+ iterator.remove()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ applicationScope.launch {
+ simBouncerInteractor.isAnySimSecure.collectLatest { isSimSecured ->
+ val iterator = callbacks.iterator()
+ withContext(backgroundDispatcher) {
+ while (iterator.hasNext()) {
+ val callback = iterator.next()
+ try {
+ callback.onSimSecureStateChanged(isSimSecured)
+ } catch (e: RemoteException) {
+ if (e is DeadObjectException) {
+ iterator.remove()
+ }
+ }
+ }
+ }
+ }
+ }
}
fun addCallback(callback: IKeyguardStateCallback) {
KeyguardWmStateRefactor.isUnexpectedlyInLegacyMode()
callbacks.add(callback)
+
+ // Send initial values to new callbacks.
+ callback.onShowingStateChanged(!isIdleInGone(), selectedUserInteractor.getSelectedUserId())
+ callback.onInputRestrictedStateChanged(!isIdleInGone())
+ callback.onTrustedChanged(trustInteractor.isTrusted.value)
+ callback.onSimSecureStateChanged(simBouncerInteractor.isAnySimSecure.value)
}
-}
\ No newline at end of file
+
+ /** Whether we're in KeyguardState.GONE and haven't started a transition to another state. */
+ private fun isIdleInGone(): Boolean {
+ return keyguardTransitionInteractor.getCurrentState() == KeyguardState.GONE &&
+ keyguardTransitionInteractor.getStartedState() == KeyguardState.GONE
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index e19b72e..c4f231d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -77,7 +77,7 @@
MutableSharedFlow<Float>(
replay = 1,
extraBufferCapacity = 2,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
.also { it.tryEmit(0f) }
}
@@ -97,8 +97,8 @@
SharingStarted.Eagerly,
WithPrev(
sceneInteractor.transitionState.value,
- sceneInteractor.transitionState.value
- )
+ sceneInteractor.transitionState.value,
+ ),
)
/**
@@ -156,7 +156,7 @@
Log.e(
TAG,
"STARTED step ($startedStep) was preceded by a RUNNING step " +
- "($prevStep), which should never happen. Things could go badly here."
+ "($prevStep), which should never happen. Things could go badly here.",
)
}
}
@@ -202,7 +202,7 @@
transitionMap.getOrPut(mappedEdge) {
MutableSharedFlow(
extraBufferCapacity = 10,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
}
@@ -262,7 +262,7 @@
is Edge.StateToState ->
Edge.create(
from = edge.from?.mapToSceneContainerState(),
- to = edge.to?.mapToSceneContainerState()
+ to = edge.to?.mapToSceneContainerState(),
)
is Edge.SceneToState -> Edge.create(UNDEFINED, edge.to)
is Edge.StateToScene -> Edge.create(edge.from, UNDEFINED)
@@ -286,9 +286,7 @@
* The value will be `0` (or close to `0`, due to float point arithmetic) if not in this step or
* `1` when fully in the given state.
*/
- fun transitionValue(
- state: KeyguardState,
- ): Flow<Float> {
+ fun transitionValue(state: KeyguardState): Flow<Float> {
if (SceneContainerFlag.isEnabled && state != state.mapToSceneContainerState()) {
Log.e(TAG, "SceneContainer is enabled but a deprecated state $state is used.")
return transitionValue(state.mapToSceneContainerScene()!!, state)
@@ -369,10 +367,9 @@
.stateIn(scope, SharingStarted.Eagerly, OFF)
val isInTransition =
- combine(
- isInTransitionWhere({ true }, { true }),
- sceneInteractor.transitionState,
- ) { isKeyguardTransitioning, sceneTransitionState ->
+ combine(isInTransitionWhere({ true }, { true }), sceneInteractor.transitionState) {
+ isKeyguardTransitioning,
+ sceneTransitionState ->
isKeyguardTransitioning ||
(SceneContainerFlag.isEnabled && sceneTransitionState.isTransitioning())
}
@@ -465,6 +462,10 @@
return currentKeyguardState.replayCache.last()
}
+ fun getStartedState(): KeyguardState {
+ return startedKeyguardTransitionStep.value.to
+ }
+
private val finishedKeyguardState: StateFlow<KeyguardState> =
repository.transitions
.filter { it.transitionState == TransitionState.FINISHED }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index 7e13d22..4b62eab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -181,7 +181,7 @@
}
.stateIn(
scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
+ started = SharingStarted.Eagerly,
initialValue =
KeyguardQuickAffordanceViewModel(
slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()
@@ -202,7 +202,7 @@
}
.stateIn(
scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
+ started = SharingStarted.Eagerly,
initialValue =
KeyguardQuickAffordanceViewModel(
slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index eaa61a1..38ca888 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -36,6 +36,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
@@ -174,6 +175,9 @@
keyguardTransitionInteractor.isInTransition(
Edge.create(from = LOCKSCREEN, to = DREAMING)
),
+ keyguardTransitionInteractor.isInTransition(
+ Edge.create(from = LOCKSCREEN, to = OCCLUDED)
+ ),
),
isOnLockscreen,
shadeInteractor.qsExpansion,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
index ecae079..3b266f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
@@ -21,13 +21,11 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.Overlays
-import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
@@ -71,9 +69,8 @@
addAll(
when (shadeMode) {
- ShadeMode.Single -> fullscreenShadeActions()
- ShadeMode.Split ->
- fullscreenShadeActions(transitionKey = ToSplitShade)
+ ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Split -> splitShadeActions()
ShadeMode.Dual -> dualShadeActions()
}
)
@@ -84,18 +81,26 @@
.collect { setActions(it) }
}
- private fun fullscreenShadeActions(
- transitionKey: TransitionKey? = null
- ): Array<Pair<UserAction, UserActionResult>> {
- val notifShadeSceneKey = UserActionResult(SceneFamilies.NotifShade, transitionKey)
- val qsShadeSceneKey = UserActionResult(SceneFamilies.QuickSettings, transitionKey)
+ private fun singleShadeActions(): Array<Pair<UserAction, UserActionResult>> {
return arrayOf(
// Swiping down, not from the edge, always goes to shade.
- Swipe.Down to notifShadeSceneKey,
- swipeDown(pointerCount = 2) to notifShadeSceneKey,
+ Swipe.Down to Scenes.Shade,
+ swipeDown(pointerCount = 2) to Scenes.Shade,
// Swiping down from the top edge goes to QS.
- swipeDownFromTop(pointerCount = 1) to qsShadeSceneKey,
- swipeDownFromTop(pointerCount = 2) to qsShadeSceneKey,
+ swipeDownFromTop(pointerCount = 1) to Scenes.QuickSettings,
+ swipeDownFromTop(pointerCount = 2) to Scenes.QuickSettings,
+ )
+ }
+
+ private fun splitShadeActions(): Array<Pair<UserAction, UserActionResult>> {
+ val splitShadeSceneKey = UserActionResult(Scenes.Shade, ToSplitShade)
+ return arrayOf(
+ // Swiping down, not from the edge, always goes to shade.
+ Swipe.Down to splitShadeSceneKey,
+ swipeDown(pointerCount = 2) to splitShadeSceneKey,
+ // Swiping down from the top edge goes to QS.
+ swipeDownFromTop(pointerCount = 1) to splitShadeSceneKey,
+ swipeDownFromTop(pointerCount = 2) to splitShadeSceneKey,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index bf9ef8c..8505a784 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -1202,13 +1202,17 @@
commonViewModels.forEach { viewModel ->
when (viewModel) {
is MediaCommonViewModel.MediaControl -> {
- controllerById[viewModel.instanceId.toString()]?.mediaViewHolder?.let {
- mediaContent.addView(it.player)
+ controllerById[viewModel.instanceId.toString()]?.let {
+ it.widthInSceneContainerPx = widthInSceneContainerPx
+ it.heightInSceneContainerPx = heightInSceneContainerPx
+ mediaContent.addView(it.mediaViewHolder?.player)
}
}
is MediaCommonViewModel.MediaRecommendations -> {
- controllerById[viewModel.key]?.recommendationViewHolder?.let {
- mediaContent.addView(it.recommendations)
+ controllerById[viewModel.key]?.let {
+ it.widthInSceneContainerPx = widthInSceneContainerPx
+ it.heightInSceneContainerPx = heightInSceneContainerPx
+ mediaContent.addView(it.recommendationViewHolder?.recommendations)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 4251b81..d596589 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -53,6 +53,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.Window;
+import android.view.WindowManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -308,6 +309,9 @@
private void setUpDialog(AlertDialog dialog) {
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.applyFlags(dialog, /* showWhenLocked= */ false);
+
+ final Window w = dialog.getWindow();
+ w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
SystemUIDialog.setDialogSize(dialog);
dialog.setOnCancelListener(this::onDialogDismissedOrCancelled);
@@ -315,7 +319,6 @@
dialog.create();
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
- final Window w = dialog.getWindow();
w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index db5a545..0d748a1 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -17,11 +17,13 @@
package com.android.systemui.model
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
@@ -57,12 +59,12 @@
val transitionState = sceneInteractor.get().transitionState.value
val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
- val currentSceneOrNull = idleTransitionStateOrNull?.currentScene
val invisibleDueToOcclusion = occlusionInteractor.get().invisibleDueToOcclusion.value
- return currentSceneOrNull?.let { sceneKey ->
+ return idleTransitionStateOrNull?.let { idleState ->
EvaluatorByFlag[flag]?.invoke(
SceneContainerPluginState(
- scene = sceneKey,
+ scene = idleState.currentScene,
+ overlays = idleState.currentOverlays,
invisibleDueToOcclusion = invisibleDueToOcclusion,
)
)
@@ -89,10 +91,15 @@
it.invisibleDueToOcclusion -> false
it.scene == Scenes.Lockscreen -> true
it.scene == Scenes.Shade -> true
+ Overlays.NotificationsShade in it.overlays -> true
else -> false
}
},
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it.scene == Scenes.QuickSettings },
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
+ {
+ it.scene == Scenes.QuickSettings ||
+ Overlays.QuickSettingsShade in it.overlays
+ },
SYSUI_STATE_BOUNCER_SHOWING to { it.scene == Scenes.Bouncer },
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
{
@@ -106,5 +113,9 @@
)
}
- data class SceneContainerPluginState(val scene: SceneKey, val invisibleDueToOcclusion: Boolean)
+ data class SceneContainerPluginState(
+ val scene: SceneKey,
+ val overlays: Set<OverlayKey>,
+ val invisibleDueToOcclusion: Boolean,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 89d76f0..f7a505a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -1335,14 +1335,16 @@
public void setBackAnimation(@Nullable BackAnimation backAnimation) {
mBackAnimation = backAnimation;
if (backAnimation != null) {
- backAnimation.setPilferPointerCallback(this::pilferPointers);
+ final Executor uiThreadExecutor = mUiThreadContext.getExecutor();
+ backAnimation.setPilferPointerCallback(
+ () -> uiThreadExecutor.execute(this::pilferPointers));
backAnimation.setTopUiRequestCallback(
- (requestTopUi, tag) -> mUiThreadContext.getExecutor().execute(() ->
+ (requestTopUi, tag) -> uiThreadExecutor.execute(() ->
mNotificationShadeWindowController.setRequestTopUi(requestTopUi, tag)));
updateBackAnimationThresholds();
if (mLightBarControllerProvider.get() != null) {
mBackAnimation.setStatusBarCustomizer((appearance) ->
- mUiThreadContext.getExecutor().execute(() ->
+ uiThreadExecutor.execute(() ->
mLightBarControllerProvider.get()
.customizeStatusBarAppearance(appearance)));
}
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
index b6868c1..63bfbd1 100644
--- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
@@ -18,9 +18,13 @@
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
+import com.android.compose.animation.scene.UserActionResult.HideOverlay
+import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -32,8 +36,10 @@
override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
setActions(
mapOf(
- Swipe.Up to UserActionResult.HideOverlay(Overlays.NotificationsShade),
- Back to UserActionResult.HideOverlay(Overlays.NotificationsShade),
+ Swipe.Up to HideOverlay(Overlays.NotificationsShade),
+ Back to HideOverlay(Overlays.NotificationsShade),
+ Swipe(direction = SwipeDirection.Down, fromSource = SceneContainerEdge.TopRight) to
+ ReplaceByOverlay(Overlays.QuickSettingsShade),
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 4018320..ca7b06a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -14,7 +14,10 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.view.InputDevice;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -191,6 +194,34 @@
}
@Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0
+ && event.getAction() == MotionEvent.ACTION_SCROLL) {
+ // Handle mouse (or ext. device) by swiping the page depending on the scroll
+ final float vscroll;
+ final float hscroll;
+ if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+ vscroll = 0;
+ hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ } else {
+ vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ }
+ if (hscroll != 0 || vscroll != 0) {
+ boolean isForwardScroll =
+ isLayoutRtl() ? (hscroll < 0 || vscroll < 0) : (hscroll > 0 || vscroll > 0);
+ int swipeDirection = isForwardScroll ? RIGHT : LEFT;
+ if (mScroller.isFinished()) {
+ scrollByX(getDeltaXForPageScrolling(swipeDirection),
+ SINGLE_PAGE_SCROLL_DURATION_MILLIS);
+ }
+ return true;
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
+ @Override
public void setCurrentItem(int item, boolean smoothScroll) {
if (isLayoutRtl()) {
item = mPages.size() - 1 - item;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
index 61c4c8c..31519a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
@@ -18,24 +18,41 @@
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
+import com.android.compose.animation.scene.UserActionResult.HideOverlay
+import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.map
/** Models the UI state for the user actions for navigating to other scenes or overlays. */
-class QuickSettingsShadeOverlayActionsViewModel @AssistedInject constructor() :
+class QuickSettingsShadeOverlayActionsViewModel
+@AssistedInject
+constructor(private val containerViewModel: QuickSettingsContainerViewModel) :
UserActionsViewModel() {
override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
- setActions(
- buildMap {
- put(Swipe.Up, UserActionResult.HideOverlay(Overlays.QuickSettingsShade))
- put(Back, UserActionResult.HideOverlay(Overlays.QuickSettingsShade))
+ containerViewModel.editModeViewModel.isEditing
+ .map { isEditing ->
+ buildMap {
+ put(Swipe.Up, HideOverlay(Overlays.QuickSettingsShade))
+ // When editing, back should go back to QS from edit mode (i.e. remain in the
+ // same overlay).
+ if (!isEditing) {
+ put(Back, HideOverlay(Overlays.QuickSettingsShade))
+ }
+ put(
+ Swipe(SwipeDirection.Down, fromSource = SceneContainerEdge.TopLeft),
+ ReplaceByOverlay(Overlays.NotificationsShade),
+ )
+ }
}
- )
+ .collect { actions -> setActions(actions) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a402a9d..ac49e91 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,10 +101,10 @@
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
-import com.android.systemui.scene.shared.model.SceneFamilies;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
@@ -158,6 +158,7 @@
private final ScreenPinningRequest mScreenPinningRequest;
private final NotificationShadeWindowController mStatusBarWinController;
private final Provider<SceneInteractor> mSceneInteractor;
+ private final Provider<ShadeInteractor> mShadeInteractor;
private final KeyboardTouchpadEduStatsInteractor mKeyboardTouchpadEduStatsInteractor;
@@ -246,11 +247,8 @@
}
} else if (action == ACTION_UP) {
// Gesture was too short to be picked up by scene container touch
- // handling; programmatically start the transition to shade scene.
- mSceneInteractor.get().changeScene(
- SceneFamilies.NotifShade,
- "short launcher swipe"
- );
+ // handling; programmatically start the transition to the shade.
+ mShadeInteractor.get().expandNotificationShade("short launcher swipe");
}
}
event.recycle();
@@ -267,10 +265,7 @@
mSceneInteractor.get().onRemoteUserInputStarted(
"trackpad swipe");
} else if (action == ACTION_UP) {
- mSceneInteractor.get().changeScene(
- SceneFamilies.NotifShade,
- "short trackpad swipe"
- );
+ mShadeInteractor.get().expandNotificationShade("short trackpad swipe");
}
mStatusBarWinController.getWindowRootView().dispatchTouchEvent(event);
} else {
@@ -652,6 +647,7 @@
NotificationShadeWindowController statusBarWinController,
SysUiState sysUiState,
Provider<SceneInteractor> sceneInteractor,
+ Provider<ShadeInteractor> shadeInteractor,
UserTracker userTracker,
UserManager userManager,
WakefulnessLifecycle wakefulnessLifecycle,
@@ -688,6 +684,7 @@
mScreenPinningRequest = screenPinningRequest;
mStatusBarWinController = statusBarWinController;
mSceneInteractor = sceneInteractor;
+ mShadeInteractor = shadeInteractor;
mUserTracker = userTracker;
mConnectionBackoffAttempts = 0;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index 1aa982f..e441a23 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -22,8 +22,6 @@
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.KeyguardStateCallbackStartable
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
@@ -47,7 +45,6 @@
EmptySceneModule::class,
GoneSceneModule::class,
NotificationsShadeOverlayModule::class,
- NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
QuickSettingsShadeOverlayModule::class,
QuickSettingsSceneModule::class,
@@ -56,8 +53,6 @@
// List SceneResolver modules for supported SceneFamilies
HomeSceneFamilyResolverModule::class,
- NotifShadeSceneFamilyResolverModule::class,
- QuickSettingsSceneFamilyResolverModule::class,
]
)
interface KeyguardlessSceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 7f0cf86..a89f752 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -22,8 +22,6 @@
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.KeyguardStateCallbackStartable
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
@@ -52,16 +50,12 @@
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
QuickSettingsShadeOverlayModule::class,
- QuickSettingsShadeSceneModule::class,
NotificationsShadeOverlayModule::class,
- NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
SceneDomainModule::class,
// List SceneResolver modules for supported SceneFamilies
HomeSceneFamilyResolverModule::class,
- NotifShadeSceneFamilyResolverModule::class,
- QuickSettingsSceneFamilyResolverModule::class,
]
)
interface SceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
index 2d40845..afb72f0 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
@@ -71,6 +71,12 @@
logger.logSceneBackStack(backStack.value.asIterable())
}
+ /** Applies the given [transform] to the back stack. */
+ fun updateBackStack(transform: (SceneStack) -> SceneStack) {
+ _backStack.update { stack -> transform(stack) }
+ logger.logSceneBackStack(backStack.value.asIterable())
+ }
+
private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? {
val fromDistance =
checkNotNull(sceneContainerConfig.navigationDistances[from]) {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index 429b47b..667827a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -16,13 +16,14 @@
package com.android.systemui.scene.domain.interactor
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardOcclusionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -117,28 +118,30 @@
private val ObservableTransitionState.canBeOccluded: Boolean
get() =
when (this) {
- is ObservableTransitionState.Idle -> currentScene.canBeOccluded
- is ObservableTransitionState.Transition.ChangeScene ->
- fromScene.canBeOccluded && toScene.canBeOccluded
- is ObservableTransitionState.Transition.ReplaceOverlay,
- is ObservableTransitionState.Transition.ShowOrHideOverlay ->
- TODO("b/359173565: Handle overlay transitions")
+ is ObservableTransitionState.Idle ->
+ currentOverlays.all { it.canBeOccluded } && currentScene.canBeOccluded
+ is ObservableTransitionState.Transition ->
+ // TODO(b/356596436): Should also verify currentOverlays.isEmpty(), but
+ // currentOverlays is a Flow and we need a state.
+ fromContent.canBeOccluded && toContent.canBeOccluded
}
/**
- * Whether the scene can be occluded by a "show when locked" activity. Some scenes should, on
+ * Whether the content can be occluded by a "show when locked" activity. Some content should, on
* principle not be occlude-able because they render as if they are expanding on top of the
* occluding activity.
*/
- private val SceneKey.canBeOccluded: Boolean
+ private val ContentKey.canBeOccluded: Boolean
get() =
when (this) {
+ Overlays.NotificationsShade -> false
+ Overlays.QuickSettingsShade -> false
Scenes.Bouncer -> false
Scenes.Communal -> true
Scenes.Gone -> true
Scenes.Lockscreen -> true
Scenes.QuickSettings -> false
Scenes.Shade -> false
- else -> error("SceneKey \"$this\" doesn't have a mapping for canBeOccluded!")
+ else -> error("ContentKey \"$this\" doesn't have a mapping for canBeOccluded!")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 0d24adc..f20e5a5 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -120,21 +120,18 @@
)
/**
- * The key of the scene that the UI is currently transitioning to or `null` if there is no
+ * The key of the content that the UI is currently transitioning to or `null` if there is no
* active transition at the moment.
*
* This is a convenience wrapper around [transitionState], meant for flow-challenged consumers
* like Java code.
*/
- val transitioningTo: StateFlow<SceneKey?> =
+ val transitioningTo: StateFlow<ContentKey?> =
transitionState
.map { state ->
when (state) {
is ObservableTransitionState.Idle -> null
- is ObservableTransitionState.Transition.ChangeScene -> state.toScene
- is ObservableTransitionState.Transition.ShowOrHideOverlay,
- is ObservableTransitionState.Transition.ReplaceOverlay ->
- TODO("b/359173565: Handle overlay transitions")
+ is ObservableTransitionState.Transition -> state.toContent
}
}
.stateIn(
@@ -160,15 +157,14 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = false,
)
/** Whether the scene container is visible. */
val isVisible: StateFlow<Boolean> =
- combine(
- repository.isVisible,
- repository.isRemoteUserInputOngoing,
- ) { isVisible, isRemoteUserInteractionOngoing ->
+ combine(repository.isVisible, repository.isRemoteUserInputOngoing) {
+ isVisible,
+ isRemoteUserInteractionOngoing ->
isVisibleInternal(
raw = isVisible,
isRemoteUserInputOngoing = isRemoteUserInteractionOngoing,
@@ -177,7 +173,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = isVisibleInternal()
+ initialValue = isVisibleInternal(),
)
/** Whether there's an ongoing remotely-initiated user interaction. */
@@ -259,10 +255,7 @@
* The change is instantaneous and not animated; it will be observable in the next frame and
* there will be no transition animation.
*/
- fun snapToScene(
- toScene: SceneKey,
- loggingReason: String,
- ) {
+ fun snapToScene(toScene: SceneKey, loggingReason: String) {
val currentSceneKey = currentScene.value
val resolvedScene =
sceneFamilyResolvers.get()[toScene]?.let { familyResolver ->
@@ -313,15 +306,9 @@
return
}
- logger.logOverlayChangeRequested(
- to = overlay,
- reason = loggingReason,
- )
+ logger.logOverlayChangeRequested(to = overlay, reason = loggingReason)
- repository.showOverlay(
- overlay = overlay,
- transitionKey = transitionKey,
- )
+ repository.showOverlay(overlay = overlay, transitionKey = transitionKey)
}
/**
@@ -345,15 +332,9 @@
return
}
- logger.logOverlayChangeRequested(
- from = overlay,
- reason = loggingReason,
- )
+ logger.logOverlayChangeRequested(from = overlay, reason = loggingReason)
- repository.hideOverlay(
- overlay = overlay,
- transitionKey = transitionKey,
- )
+ repository.hideOverlay(overlay = overlay, transitionKey = transitionKey)
}
/**
@@ -378,17 +359,9 @@
return
}
- logger.logOverlayChangeRequested(
- from = from,
- to = to,
- reason = loggingReason,
- )
+ logger.logOverlayChangeRequested(from = from, to = to, reason = loggingReason)
- repository.replaceOverlay(
- from = from,
- to = to,
- transitionKey = transitionKey,
- )
+ repository.replaceOverlay(from = from, to = to, transitionKey = transitionKey)
}
/**
@@ -405,11 +378,7 @@
return
}
- logger.logVisibilityChange(
- from = wasVisible,
- to = isVisible,
- reason = loggingReason,
- )
+ logger.logVisibilityChange(from = wasVisible, to = isVisible, reason = loggingReason)
return repository.setVisible(isVisible)
}
@@ -491,11 +460,7 @@
* @param loggingReason The reason why the transition is requested, for logging purposes
* @return `true` if the scene change is valid; `false` if it shouldn't happen
*/
- private fun validateSceneChange(
- from: SceneKey,
- to: SceneKey,
- loggingReason: String,
- ): Boolean {
+ private fun validateSceneChange(from: SceneKey, to: SceneKey, loggingReason: String): Boolean {
if (to !in repository.allContentKeys) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
deleted file mode 100644
index a313273..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.domain.resolver
-
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-@SysUISingleton
-class NotifShadeSceneFamilyResolver
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- shadeModeInteractor: ShadeModeInteractor,
-) : SceneResolver {
- override val targetFamily: SceneKey = SceneFamilies.NotifShade
-
- override val resolvedScene: StateFlow<SceneKey> =
- shadeModeInteractor.shadeMode
- .map(::notifShadeScene)
- .stateIn(
- applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = notifShadeScene(shadeModeInteractor.shadeMode.value),
- )
-
- override fun includesScene(scene: SceneKey): Boolean = scene in notifShadeScenes
-
- private fun notifShadeScene(shadeMode: ShadeMode) =
- when (shadeMode) {
- is ShadeMode.Single -> Scenes.Shade
- is ShadeMode.Dual -> Scenes.NotificationsShade
- is ShadeMode.Split -> Scenes.Shade
- }
-
- companion object {
- val notifShadeScenes = setOf(Scenes.NotificationsShade, Scenes.Shade)
- }
-}
-
-@Module
-interface NotifShadeSceneFamilyResolverModule {
- @Binds @IntoSet fun bindResolver(interactor: NotifShadeSceneFamilyResolver): SceneResolver
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
deleted file mode 100644
index 923e712a..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.domain.resolver
-
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-@SysUISingleton
-class QuickSettingsSceneFamilyResolver
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- shadeModeInteractor: ShadeModeInteractor,
-) : SceneResolver {
- override val targetFamily: SceneKey = SceneFamilies.QuickSettings
-
- override val resolvedScene: StateFlow<SceneKey> =
- shadeModeInteractor.shadeMode
- .map(::quickSettingsScene)
- .stateIn(
- applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = quickSettingsScene(shadeModeInteractor.shadeMode.value),
- )
-
- override fun includesScene(scene: SceneKey): Boolean = scene in quickSettingsScenes
-
- private fun quickSettingsScene(shadeMode: ShadeMode) =
- when (shadeMode) {
- is ShadeMode.Single -> Scenes.QuickSettings
- is ShadeMode.Dual -> Scenes.QuickSettingsShade
- is ShadeMode.Split -> Scenes.Shade
- }
-
- companion object {
- val quickSettingsScenes =
- setOf(Scenes.QuickSettings, Scenes.QuickSettingsShade, Scenes.Shade)
- }
-}
-
-@Module
-interface QuickSettingsSceneFamilyResolverModule {
- @Binds @IntoSet fun bindResolver(interactor: QuickSettingsSceneFamilyResolver): SceneResolver
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 18767f5..e11ffcc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -45,7 +45,6 @@
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor
import com.android.systemui.model.SceneContainerPlugin
import com.android.systemui.model.SysUiState
@@ -55,6 +54,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.sceneStackOf
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -107,6 +107,7 @@
* Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
* scene container based on state from other systems.
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class SceneContainerStartable
@Inject
@@ -118,7 +119,6 @@
private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
private val bouncerInteractor: BouncerInteractor,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val sysUiState: SysUiState,
@DisplayId private val displayId: Int,
private val sceneLogger: SceneLogger,
@@ -281,6 +281,8 @@
applicationScope.launch {
sceneInteractor.currentScene.collectLatest { currentScene ->
if (currentScene == Scenes.Lockscreen) {
+ // Wait for the screen to be on
+ powerInteractor.isAwake.first { it }
// Wait for surface to become visible
windowMgrLockscreenVisInteractor.surfaceBehindVisibility.first { it }
// Make sure the device is actually unlocked before force-changing the scene
@@ -407,8 +409,7 @@
}
isOnPrimaryBouncer -> {
// When the device becomes unlocked in primary Bouncer,
- // notify dismiss succeeded and
- // go to previous scene or Gone.
+ // notify dismiss succeeded and go to previous scene or Gone.
dismissCallbackRegistry.notifyDismissSucceeded()
if (
previousScene.value == Scenes.Lockscreen ||
@@ -419,7 +420,20 @@
" didn't need to be left open"
} else {
val prevScene = previousScene.value
- (prevScene ?: Scenes.Gone) to
+ val targetScene = prevScene ?: Scenes.Gone
+ if (targetScene != Scenes.Gone) {
+ sceneBackInteractor.updateBackStack { stack ->
+ val list = stack.asIterable().toMutableList()
+ check(list.last() == Scenes.Lockscreen) {
+ "The bottommost/last SceneKey of the back stack isn't" +
+ " the Lockscreen scene like expected. The back" +
+ " stack is $stack."
+ }
+ list[list.size - 1] = Scenes.Gone
+ sceneStackOf(*list.toTypedArray())
+ }
+ }
+ targetScene to
"device was unlocked with primary bouncer showing," +
" from sceneKey=$prevScene"
}
@@ -582,12 +596,12 @@
combine(
sceneInteractor.transitionState
.mapNotNull { it as? ObservableTransitionState.Idle }
- .map { it.currentScene }
.distinctUntilChanged(),
occlusionInteractor.invisibleDueToOcclusion,
- ) { sceneKey, invisibleDueToOcclusion ->
+ ) { idleState, invisibleDueToOcclusion ->
SceneContainerPlugin.SceneContainerPluginState(
- scene = sceneKey,
+ scene = idleState.currentScene,
+ overlays = idleState.currentOverlays,
invisibleDueToOcclusion = invisibleDueToOcclusion,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
index 115d664..82b4b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
@@ -43,22 +43,6 @@
@JvmField val Lockscreen = SceneKey("lockscreen")
/**
- * The notifications shade scene primarily shows a scrollable list of notifications as an
- * overlay UI.
- *
- * It's used only in the dual shade configuration, where there are two separate shades: one for
- * notifications (this scene) and another for [QuickSettingsShade].
- *
- * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) or in the "split" shade configuration (on
- * large screens or unfolded foldables, where notifications and quick settings are shown
- * side-by-side in their own columns).
- */
- @Deprecated("The notifications shade scene has been replaced by an overlay")
- @JvmField
- val NotificationsShade = SceneKey("notifications_shade")
-
- /**
* The quick settings scene shows the quick setting tiles.
*
* This scene is used for single/accordion configuration (swipe down once to reveal the shade,
@@ -69,27 +53,12 @@
* scene is used.
*
* For the dual shade configuration, where there are two separate shades: one for notifications
- * and one for quick settings, [NotificationsShade] and [QuickSettingsShade] scenes are used
- * respectively.
+ * and one for quick settings, the overlays `NotificationsShade` and `QuickSettingsShade` are
+ * used respectively.
*/
@JvmField val QuickSettings = SceneKey("quick_settings")
/**
- * The quick settings shade scene shows the quick setting tiles as an overlay UI.
- *
- * It's used only in the dual shade configuration, where there are two separate shades: one for
- * quick settings (this scene) and another for [NotificationsShade].
- *
- * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) or in the "split" shade configuration (on
- * large screens or unfolded foldables, where notifications and quick settings are shown
- * side-by-side in their own columns).
- */
- @Deprecated("The quick settings shade scene has been replaced by an overlay")
- @JvmField
- val QuickSettingsShade = SceneKey("quick_settings_shade")
-
- /**
* The shade is the scene that shows a scrollable list of notifications and the minimized
* version of quick settings (AKA "quick quick settings" or "QQS").
*
@@ -97,7 +66,8 @@
* swipe down again the to expand quick settings) and for the "split" shade configuration (on
* large screens or unfolded foldables, where notifications and quick settings are shown
* side-by-side in their own columns). For the dual shade configuration, where there are two
- * separate shades: one for notifications and one for quick settings, other scenes are used.
+ * separate shades: one for notifications and one for quick settings, the overlays
+ * `NotificationsShade` and `QuickSettingsShade` are used respectively.
*/
@JvmField val Shade = SceneKey("shade")
}
@@ -114,16 +84,4 @@
* depending on whether the device is unlocked and has been entered.
*/
@JvmField val Home = SceneKey(debugName = "scene_family_home")
-
- /**
- * The scene that contains the full, interactive notification shade. The specific scene it
- * resolves to can depend on dual / split / single shade settings.
- */
- @JvmField val NotifShade = SceneKey(debugName = "scene_family_notif_shade")
-
- /**
- * The scene that contains the full QuickSettings (not to be confused with Quick-QuickSettings).
- * The specific scene it resolves to can depend on dual / split / single shade settings.
- */
- @JvmField val QuickSettings = SceneKey(debugName = "scene_family_quick_settings")
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index c451704..af1f5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -52,7 +52,7 @@
private val sceneInteractor: SceneInteractor,
private val falsingInteractor: FalsingInteractor,
private val powerInteractor: PowerInteractor,
- private val shadeInteractor: ShadeInteractor,
+ shadeInteractor: ShadeInteractor,
private val splitEdgeDetector: SplitEdgeDetector,
private val logger: SceneLogger,
@Assisted private val motionEventHandlerReceiver: (MotionEventHandler?) -> Unit,
@@ -212,9 +212,10 @@
)
}
}
+ // Overlay transitions don't use scene families, nothing to resolve.
is UserActionResult.ShowOverlay,
is UserActionResult.HideOverlay,
- is UserActionResult.ReplaceByOverlay -> TODO("b/353679003: Support overlays")
+ is UserActionResult.ReplaceByOverlay -> null
} ?: actionResult
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index d4e711e..663ba20 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -41,7 +41,6 @@
import androidx.exifinterface.media.ExifInterface;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.flags.FeatureFlags;
import com.google.common.util.concurrent.ListenableFuture;
@@ -94,12 +93,10 @@
private final ContentResolver mResolver;
private CompressFormat mCompressFormat = CompressFormat.PNG;
private int mQuality = 100;
- private final FeatureFlags mFlags;
@Inject
- public ImageExporter(ContentResolver resolver, FeatureFlags flags) {
+ public ImageExporter(ContentResolver resolver) {
mResolver = resolver;
- mFlags = flags;
}
/**
@@ -161,8 +158,7 @@
ZonedDateTime captureTime = ZonedDateTime.now(ZoneId.systemDefault());
return export(executor,
new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
- mQuality, /* publish */ true, owner, mFlags,
- createFilename(captureTime, mCompressFormat, displayId)));
+ mQuality, owner, createFilename(captureTime, mCompressFormat, displayId)));
}
/**
@@ -184,7 +180,8 @@
bitmap,
ZonedDateTime.now(ZoneId.systemDefault()),
format,
- mQuality, /* publish */ true, owner, mFlags,
+ mQuality,
+ owner,
createSystemFileDisplayName(fileName, format),
true /* allowOverwrite */));
}
@@ -199,8 +196,7 @@
public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
ZonedDateTime captureTime, UserHandle owner, int displayId) {
return export(executor, new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
- mQuality, /* publish */ true, owner, mFlags,
- createFilename(captureTime, mCompressFormat, displayId)));
+ mQuality, owner, createFilename(captureTime, mCompressFormat, displayId)));
}
/**
@@ -213,8 +209,7 @@
ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
ZonedDateTime captureTime, UserHandle owner, String fileName) {
return export(executor, new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
- mQuality, /* publish */ true, owner, mFlags,
- createSystemFileDisplayName(fileName, mCompressFormat)));
+ mQuality, owner, createSystemFileDisplayName(fileName, mCompressFormat)));
}
/**
@@ -249,7 +244,6 @@
public String fileName;
public long timestamp;
public CompressFormat format;
- public boolean published;
@Override
public String toString() {
@@ -259,7 +253,6 @@
sb.append(", fileName='").append(fileName).append('\'');
sb.append(", timestamp=").append(timestamp);
sb.append(", format=").append(format);
- sb.append(", published=").append(published);
sb.append('}');
return sb.toString();
}
@@ -274,8 +267,6 @@
private final int mQuality;
private final UserHandle mOwner;
private final String mFileName;
- private final boolean mPublish;
- private final FeatureFlags mFlags;
/**
* This variable specifies the behavior when a file to be exported has a same name and
@@ -287,15 +278,14 @@
private final boolean mAllowOverwrite;
Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
- CompressFormat format, int quality, boolean publish, UserHandle owner,
- FeatureFlags flags, String fileName) {
- this(resolver, requestId, bitmap, captureTime, format, quality, publish, owner, flags,
- fileName, false /* allowOverwrite */);
+ CompressFormat format, int quality, UserHandle owner, String fileName) {
+ this(resolver, requestId, bitmap, captureTime, format, quality, owner, fileName,
+ false /* allowOverwrite */);
}
Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
- CompressFormat format, int quality, boolean publish, UserHandle owner,
- FeatureFlags flags, String fileName, boolean allowOverwrite) {
+ CompressFormat format, int quality, UserHandle owner,
+ String fileName, boolean allowOverwrite) {
mResolver = resolver;
mRequestId = requestId;
mBitmap = bitmap;
@@ -304,8 +294,6 @@
mQuality = quality;
mOwner = owner;
mFileName = fileName;
- mPublish = publish;
- mFlags = flags;
mAllowOverwrite = allowOverwrite;
}
@@ -320,7 +308,7 @@
start = Instant.now();
}
- uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner, mFlags,
+ uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner,
mAllowOverwrite);
throwIfInterrupted();
@@ -332,10 +320,7 @@
writeExif(mResolver, uri, mRequestId, width, height, mCaptureTime);
throwIfInterrupted();
- if (mPublish) {
- publishEntry(mResolver, uri);
- result.published = true;
- }
+ publishEntry(mResolver, uri);
result.timestamp = mCaptureTime.toInstant().toEpochMilli();
result.requestId = mRequestId;
@@ -365,7 +350,7 @@
}
private static Uri createEntry(ContentResolver resolver, CompressFormat format,
- ZonedDateTime time, String fileName, UserHandle owner, FeatureFlags flags,
+ ZonedDateTime time, String fileName, UserHandle owner,
boolean allowOverwrite) throws ImageExportException {
Trace.beginSection("ImageExporter_createEntry");
try {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 31813b2..42499f0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -207,7 +207,7 @@
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 813df11..859926c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -245,10 +245,6 @@
/** */
default void setNotificationPresenter(NotificationPresenter presenter) {}
- /** */
- default void setNotificationShadeWindowViewController(
- NotificationShadeWindowViewController notificationShadeWindowViewController) {}
-
/** Listens for shade visibility changes. */
interface ShadeVisibilityListener {
/** Called when shade expanded and visible state changed. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 07836e4..b7a95e9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -65,6 +65,7 @@
private final StatusBarWindowController mStatusBarWindowController;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final Lazy<NotificationShadeWindowViewController> mNotifShadeWindowViewController;
private final Lazy<NotificationPanelViewController> mNpvc;
private final Lazy<AssistManager> mAssistManagerLazy;
private final Lazy<NotificationGutsManager> mGutsManager;
@@ -72,7 +73,6 @@
private boolean mExpandedVisible;
private boolean mLockscreenOrShadeVisible;
- private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
private ShadeVisibilityListener mShadeVisibilityListener;
@Inject
@@ -87,6 +87,7 @@
DeviceProvisionedController deviceProvisionedController,
NotificationShadeWindowController notificationShadeWindowController,
@DisplayId int displayId,
+ Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewController,
Lazy<NotificationPanelViewController> shadeViewControllerLazy,
Lazy<AssistManager> assistManagerLazy,
Lazy<NotificationGutsManager> gutsManager
@@ -105,6 +106,7 @@
mDeviceProvisionedController = deviceProvisionedController;
mGutsManager = gutsManager;
mNotificationShadeWindowController = notificationShadeWindowController;
+ mNotifShadeWindowViewController = notificationShadeWindowViewController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mDisplayId = displayId;
mKeyguardStateController = keyguardStateController;
@@ -139,7 +141,7 @@
// release focus immediately to kick off focus change transition
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
- mNotificationShadeWindowViewController.cancelExpandHelper();
+ mNotifShadeWindowViewController.get().cancelExpandHelper();
getNpvc().collapse(true, delayed, speedUpFactor);
}
}
@@ -242,7 +244,7 @@
@Override
public void cancelExpansionAndCollapseShade() {
if (getNpvc().isTracking()) {
- mNotificationShadeWindowViewController.cancelCurrentTouch();
+ mNotifShadeWindowViewController.get().cancelCurrentTouch();
}
if (getNpvc().isPanelExpanded()
&& mStatusBarStateController.getState() == StatusBarState.SHADE) {
@@ -367,14 +369,8 @@
mShadeVisibilityListener.expandedVisibleChanged(expandedVisible);
}
- @Override
- public void setNotificationShadeWindowViewController(
- NotificationShadeWindowViewController controller) {
- mNotificationShadeWindowViewController = controller;
- }
-
private NotificationShadeWindowView getNotificationShadeWindowView() {
- return mNotificationShadeWindowViewController.getView();
+ return mNotifShadeWindowViewController.get().getView();
}
private NotificationPanelViewController getNpvc() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 5d03a28..361226a4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -91,17 +91,14 @@
}
override fun instantCollapseShade() {
- sceneInteractor.snapToScene(
- SceneFamilies.Home,
- "hide shade",
- )
+ sceneInteractor.snapToScene(SceneFamilies.Home, "hide shade")
}
override fun animateCollapseShade(
flags: Int,
force: Boolean,
delayed: Boolean,
- speedUpFactor: Float
+ speedUpFactor: Float,
) {
if (!force && !shadeInteractor.isAnyExpanded.value) {
runPostCollapseActions()
@@ -147,7 +144,7 @@
if (shadeInteractor.isAnyExpanded.value) {
commandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */
+ true, /* force */
)
assistManagerLazy.get().hideAssist()
}
@@ -172,17 +169,11 @@
}
override fun expandToNotifications() {
- sceneInteractor.changeScene(
- SceneFamilies.NotifShade,
- "ShadeController.animateExpandShade",
- )
+ shadeInteractor.expandNotificationShade("ShadeController.animateExpandShade")
}
override fun expandToQs() {
- sceneInteractor.changeScene(
- SceneFamilies.QuickSettings,
- "ShadeController.animateExpandQs",
- )
+ shadeInteractor.expandQuickSettingsShade("ShadeController.animateExpandQs")
}
override fun setVisibilityListener(listener: ShadeVisibilityListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index c49cfbd..cb589aa 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -194,6 +194,7 @@
if (qsVisible && field != value) {
header.alpha = ShadeInterpolation.getContentAlpha(value)
field = value
+ updateIgnoredSlots()
}
}
@@ -538,7 +539,7 @@
private fun updateIgnoredSlots() {
// switching from QQS to QS state halfway through the transition
- if (singleCarrier || qsExpandedFraction < 0.5) {
+ if (singleCarrier || (!largeScreenActive && qsExpandedFraction < 0.5)) {
iconContainer.removeIgnoredSlots(carrierIconSlots)
} else {
iconContainer.addIgnoredSlots(carrierIconSlots)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
index e276f88..cea521f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
@@ -18,10 +18,11 @@
package com.android.systemui.shade.domain.interactor
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.SysuiStatusBarStateController
import javax.inject.Inject
@@ -55,7 +56,9 @@
when (state) {
is ObservableTransitionState.Idle ->
flowOf(
- if (state.currentScene != Scenes.Gone) {
+ if (
+ state.currentScene != Scenes.Gone || state.currentOverlays.isNotEmpty()
+ ) {
// When resting on a non-Gone scene, the panel is fully expanded.
1f
} else {
@@ -64,10 +67,10 @@
0f
}
)
- is ObservableTransitionState.Transition.ChangeScene ->
+ is ObservableTransitionState.Transition ->
when {
- state.fromScene == Scenes.Gone ->
- if (state.toScene.isExpandable()) {
+ state.fromContent == Scenes.Gone ->
+ if (state.toContent.isExpandable()) {
// Moving from Gone to a scene that can animate-expand has a
// panel expansion that tracks with the transition.
state.progress
@@ -76,8 +79,8 @@
// immediately makes the panel fully expanded.
flowOf(1f)
}
- state.toScene == Scenes.Gone ->
- if (state.fromScene.isExpandable()) {
+ state.toContent == Scenes.Gone ->
+ if (state.fromContent.isExpandable()) {
// Moving to Gone from a scene that can animate-expand has a
// panel expansion that tracks with the transition.
state.progress.map { 1 - it }
@@ -88,9 +91,6 @@
}
else -> flowOf(1f)
}
- is ObservableTransitionState.Transition.ShowOrHideOverlay,
- is ObservableTransitionState.Transition.ReplaceOverlay ->
- TODO("b/359173565: Handle overlay transitions")
}
}
@@ -132,7 +132,13 @@
return sceneInteractor.currentScene.value == Scenes.Lockscreen
}
- private fun SceneKey.isExpandable(): Boolean {
- return this == Scenes.Shade || this == Scenes.QuickSettings
+ private fun ContentKey.isExpandable(): Boolean {
+ return when (this) {
+ Scenes.Shade,
+ Scenes.QuickSettings,
+ Overlays.NotificationsShade,
+ Overlays.QuickSettingsShade -> true
+ else -> false
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6fb96da..b046c50 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -140,6 +140,18 @@
* animating.
*/
val isUserInteractingWithQs: Flow<Boolean>
+
+ /**
+ * Triggers the expansion (opening) of the notification shade. If the notification shade is
+ * already open, this has no effect.
+ */
+ fun expandNotificationShade(loggingReason: String)
+
+ /**
+ * Triggers the expansion (opening) of the quick settings shade. If the quick settings shade is
+ * already open, this has no effect.
+ */
+ fun expandQuickSettingsShade(loggingReason: String)
}
fun createAnyExpansionFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index 6c0b55a..fb14828 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -49,4 +49,8 @@
override val isShadeLayoutWide: StateFlow<Boolean> = inactiveFlowBoolean
override fun getTopEdgeSplitFraction(): Float = 0.5f
+
+ override fun expandNotificationShade(loggingReason: String) {}
+
+ override fun expandQuickSettingsShade(loggingReason: String) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
index f48e31e..df09486 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
@@ -61,7 +61,7 @@
keyguardRepository.statusBarState,
repository.legacyShadeExpansion,
repository.qsExpansion,
- sharedNotificationContainerInteractor.isSplitShadeEnabled
+ sharedNotificationContainerInteractor.isSplitShadeEnabled,
) {
lockscreenShadeExpansion,
statusBarState,
@@ -97,13 +97,13 @@
repository.legacyExpandedOrAwaitingInputTransfer.stateIn(
scope,
SharingStarted.Eagerly,
- false
+ false,
)
override val isUserInteractingWithShade: Flow<Boolean> =
combine(
userInteractingFlow(repository.legacyShadeTracking, repository.legacyShadeExpansion),
- repository.legacyLockscreenShadeTracking
+ repository.legacyLockscreenShadeTracking,
) { legacyShadeTracking, legacyLockscreenShadeTracking ->
legacyShadeTracking || legacyLockscreenShadeTracking
}
@@ -111,6 +111,18 @@
override val isUserInteractingWithQs: Flow<Boolean> =
userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion)
+ override fun expandNotificationShade(loggingReason: String) {
+ throw UnsupportedOperationException(
+ "expandNotificationShade() is not supported in legacy shade"
+ )
+ }
+
+ override fun expandQuickSettingsShade(loggingReason: String) {
+ throw UnsupportedOperationException(
+ "expandQuickSettingsShade() is not supported in legacy shade"
+ )
+ }
+
/**
* Return a flow for whether a user is interacting with an expandable shade component using
* tracking and expansion flows. NOTE: expansion must be a `StateFlow` to guarantee that
@@ -118,7 +130,7 @@
*/
private fun userInteractingFlow(
tracking: Flow<Boolean>,
- expansion: StateFlow<Float>
+ expansion: StateFlow<Float>,
): Flow<Boolean> {
return flow {
// initial value is false
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index e84cfa5..81bf712 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -17,81 +17,70 @@
package com.android.systemui.shade.domain.interactor
import com.android.app.tracing.FlowTracing.traceAsCounter
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** ShadeInteractor implementation for Scene Container. */
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class ShadeInteractorSceneContainerImpl
@Inject
constructor(
@Application scope: CoroutineScope,
- sceneInteractor: SceneInteractor,
- shadeRepository: ShadeRepository,
+ private val sceneInteractor: SceneInteractor,
+ private val shadeModeInteractor: ShadeModeInteractor,
) : BaseShadeInteractor {
init {
SceneContainerFlag.assertInNewMode()
}
override val shadeExpansion: StateFlow<Float> =
- sceneBasedExpansion(sceneInteractor, SceneFamilies.NotifShade)
+ shadeModeInteractor.shadeMode
+ .flatMapLatest { shadeMode ->
+ transitionProgressExpansion(shadeMode.notificationsContentKey)
+ }
.traceAsCounter("panel_expansion") { (it * 100f).toInt() }
.stateIn(scope, SharingStarted.Eagerly, 0f)
- private val sceneBasedQsExpansion =
- sceneBasedExpansion(sceneInteractor, SceneFamilies.QuickSettings)
-
override val qsExpansion: StateFlow<Float> =
- combine(
- shadeRepository.isShadeLayoutWide,
- shadeExpansion,
- sceneBasedQsExpansion,
- ) { isSplitShadeEnabled, shadeExpansion, qsExpansion ->
- if (isSplitShadeEnabled) {
- shadeExpansion
- } else {
- qsExpansion
- }
- }
+ shadeModeInteractor.shadeMode
+ .flatMapLatest { shadeMode -> transitionProgressExpansion(shadeMode.qsContentKey) }
.stateIn(scope, SharingStarted.Eagerly, 0f)
override val isQsExpanded: StateFlow<Boolean> =
- qsExpansion
- .map { it > 0 }
- .distinctUntilChanged()
- .stateIn(scope, SharingStarted.Eagerly, false)
+ qsExpansion.map { it > 0 }.stateIn(scope, SharingStarted.Eagerly, false)
override val isQsBypassingShade: Flow<Boolean> =
- combine(
- sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
- sceneInteractor.resolveSceneFamily(SceneFamilies.NotifShade),
- ::Pair
- )
- .flatMapLatestConflated { (quickSettingsScene, notificationsScene) ->
+ shadeModeInteractor.shadeMode
+ .flatMapLatestConflated { shadeMode ->
sceneInteractor.transitionState
.map { state ->
when (state) {
is ObservableTransitionState.Idle -> false
is ObservableTransitionState.Transition ->
- state.toContent == quickSettingsScene &&
- state.fromContent != notificationsScene
+ state.toContent == shadeMode.qsContentKey &&
+ state.fromContent != shadeMode.notificationsContentKey
}
}
.distinctUntilChanged()
@@ -99,21 +88,22 @@
.distinctUntilChanged()
override val isQsFullscreen: Flow<Boolean> =
- combine(
- shadeRepository.isShadeLayoutWide,
- sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
- ::Pair
- )
- .flatMapLatestConflated { (isShadeLayoutWide, quickSettingsScene) ->
- sceneInteractor.transitionState
- .map { state ->
- when (state) {
- is ObservableTransitionState.Idle ->
- !isShadeLayoutWide && state.currentScene == quickSettingsScene
- is ObservableTransitionState.Transition -> false
- }
- }
- .distinctUntilChanged()
+ shadeModeInteractor.shadeMode
+ .flatMapLatest { shadeMode ->
+ when (shadeMode) {
+ ShadeMode.Single ->
+ sceneInteractor.transitionState
+ .map { state ->
+ when (state) {
+ is ObservableTransitionState.Idle ->
+ state.currentScene == Scenes.QuickSettings
+ is ObservableTransitionState.Transition -> false
+ }
+ }
+ .distinctUntilChanged()
+ ShadeMode.Split,
+ ShadeMode.Dual -> flowOf(false)
+ }
}
.distinctUntilChanged()
@@ -121,16 +111,79 @@
createAnyExpansionFlow(scope, shadeExpansion, qsExpansion)
override val isAnyExpanded =
- anyExpansion
- .map { it > 0f }
- .distinctUntilChanged()
- .stateIn(scope, SharingStarted.Eagerly, false)
+ anyExpansion.map { it > 0f }.stateIn(scope, SharingStarted.Eagerly, false)
override val isUserInteractingWithShade: Flow<Boolean> =
- sceneBasedInteracting(sceneInteractor, SceneFamilies.NotifShade)
+ shadeModeInteractor.shadeMode.flatMapLatest { shadeMode ->
+ when (shadeMode) {
+ ShadeMode.Single,
+ ShadeMode.Split -> sceneBasedInteracting(sceneInteractor, Scenes.Shade)
+ ShadeMode.Dual ->
+ overlayBasedInteracting(sceneInteractor, Overlays.NotificationsShade)
+ }
+ }
override val isUserInteractingWithQs: Flow<Boolean> =
- sceneBasedInteracting(sceneInteractor, SceneFamilies.QuickSettings)
+ shadeModeInteractor.shadeMode.flatMapLatest { shadeMode ->
+ when (shadeMode) {
+ ShadeMode.Single -> sceneBasedInteracting(sceneInteractor, Scenes.QuickSettings)
+ ShadeMode.Split -> sceneBasedInteracting(sceneInteractor, Scenes.Shade)
+ ShadeMode.Dual ->
+ overlayBasedInteracting(sceneInteractor, Overlays.QuickSettingsShade)
+ }
+ }
+
+ override fun expandNotificationShade(loggingReason: String) {
+ if (shadeModeInteractor.isDualShade) {
+ if (Overlays.QuickSettingsShade in sceneInteractor.currentOverlays.value) {
+ sceneInteractor.replaceOverlay(
+ from = Overlays.QuickSettingsShade,
+ to = Overlays.NotificationsShade,
+ loggingReason = loggingReason,
+ )
+ } else {
+ sceneInteractor.showOverlay(
+ overlay = Overlays.NotificationsShade,
+ loggingReason = loggingReason,
+ )
+ }
+ } else {
+ sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = loggingReason)
+ }
+ }
+
+ override fun expandQuickSettingsShade(loggingReason: String) {
+ if (shadeModeInteractor.isDualShade) {
+ if (Overlays.NotificationsShade in sceneInteractor.currentOverlays.value) {
+ sceneInteractor.replaceOverlay(
+ from = Overlays.NotificationsShade,
+ to = Overlays.QuickSettingsShade,
+ loggingReason = loggingReason,
+ )
+ } else {
+ sceneInteractor.showOverlay(
+ overlay = Overlays.QuickSettingsShade,
+ loggingReason = loggingReason,
+ )
+ }
+ } else {
+ sceneInteractor.changeScene(
+ toScene = Scenes.QuickSettings,
+ loggingReason = loggingReason,
+ )
+ }
+ }
+
+ /**
+ * Returns a flow that uses scene transition progress to and from a content to a 0-1 expansion
+ * amount float.
+ */
+ private fun transitionProgressExpansion(contentKey: ContentKey): Flow<Float> {
+ return when (contentKey) {
+ is SceneKey -> sceneBasedExpansion(sceneInteractor, contentKey)
+ is OverlayKey -> overlayBasedExpansion(sceneInteractor, contentKey)
+ }
+ }
/**
* Returns a flow that uses scene transition progress to and from a scene that is pulled down
@@ -181,4 +234,60 @@
}
}
.distinctUntilChanged()
+
+ /**
+ * Returns a flow that uses scene transition progress to and from [overlay] to a 0-1 expansion
+ * amount float.
+ */
+ private fun overlayBasedExpansion(sceneInteractor: SceneInteractor, overlay: OverlayKey) =
+ sceneInteractor.transitionState
+ .flatMapLatestConflated { state ->
+ when (state) {
+ is ObservableTransitionState.Idle ->
+ flowOf(if (overlay in state.currentOverlays) 1f else 0f)
+ is ObservableTransitionState.Transition ->
+ if (state.toContent == overlay) {
+ state.progress
+ } else if (state.fromContent == overlay) {
+ state.progress.map { progress -> 1 - progress }
+ } else {
+ flowOf(0f)
+ }
+ }
+ }
+ .distinctUntilChanged()
+
+ /**
+ * Returns a flow that uses scene transition data to determine whether the user is interacting
+ * with [overlay].
+ */
+ private fun overlayBasedInteracting(sceneInteractor: SceneInteractor, overlay: OverlayKey) =
+ sceneInteractor.transitionState
+ .map { state ->
+ when (state) {
+ is ObservableTransitionState.Idle -> false
+ is ObservableTransitionState.Transition ->
+ state.isInitiatedByUserInput &&
+ (state.toContent == overlay || state.fromContent == overlay)
+ }
+ }
+ .distinctUntilChanged()
+
+ private val ShadeMode.notificationsContentKey: ContentKey
+ get() {
+ return when (this) {
+ ShadeMode.Single,
+ ShadeMode.Split -> Scenes.Shade
+ ShadeMode.Dual -> Overlays.NotificationsShade
+ }
+ }
+
+ private val ShadeMode.qsContentKey: ContentKey
+ get() {
+ return when (this) {
+ ShadeMode.Single -> Scenes.QuickSettings
+ ShadeMode.Split -> Scenes.Shade
+ ShadeMode.Dual -> Overlays.QuickSettingsShade
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
index e525b86..0fb3790 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
@@ -21,9 +21,10 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -45,10 +46,14 @@
override val udfpsTransitionToFullShadeProgress =
shadeRepository.udfpsTransitionToFullShadeProgress
+ @Deprecated("Use ShadeInteractor instead")
override fun expandToNotifications() {
- changeToShadeScene()
+ shadeInteractor.expandNotificationShade(
+ loggingReason = "ShadeLockscreenInteractorImpl.expandToNotifications"
+ )
}
+ @Deprecated("Use ShadeInteractor instead")
override val isExpanded
get() = shadeInteractor.isAnyExpanded.value
@@ -60,15 +65,26 @@
lockIconViewController.dozeTimeTick()
}
+ @Deprecated("Not supported by scenes")
override fun blockExpansionForCurrentTouch() {
// TODO("b/324280998") Implement replacement or delete
}
override fun resetViews(animate: Boolean) {
+ val loggingReason = "ShadeLockscreenInteractorImpl.resetViews"
// The existing comment to the only call to this claims it only calls it to collapse QS
- changeToShadeScene()
+ if (shadeInteractor.shadeMode.value == ShadeMode.Dual) {
+ // TODO(b/356596436): Hide without animation if !animate.
+ sceneInteractor.hideOverlay(
+ overlay = Overlays.QuickSettingsShade,
+ loggingReason = loggingReason,
+ )
+ } else {
+ shadeInteractor.expandNotificationShade(loggingReason)
+ }
}
+ @Deprecated("Not supported by scenes")
override fun setPulsing(pulsing: Boolean) {
// Now handled elsewhere. Do nothing.
}
@@ -76,22 +92,30 @@
override fun transitionToExpandedShade(delay: Long) {
backgroundScope.launch {
delay(delay)
- withContext(mainDispatcher) { changeToShadeScene() }
+ withContext(mainDispatcher) {
+ shadeInteractor.expandNotificationShade(
+ "ShadeLockscreenInteractorImpl.transitionToExpandedShade"
+ )
+ }
}
}
+ @Deprecated("Not supported by scenes")
override fun resetViewGroupFade() {
// Now handled elsewhere. Do nothing.
}
+ @Deprecated("Not supported by scenes")
override fun setKeyguardTransitionProgress(keyguardAlpha: Float, keyguardTranslationY: Int) {
// Now handled elsewhere. Do nothing.
}
+ @Deprecated("Not supported by scenes")
override fun setOverStretchAmount(amount: Float) {
// Now handled elsewhere. Do nothing.
}
+ @Deprecated("TODO(b/325072511) delete this")
override fun setKeyguardStatusBarAlpha(alpha: Float) {
// TODO(b/325072511) delete this
}
@@ -100,11 +124,4 @@
sceneInteractor.changeScene(Scenes.Lockscreen, "showAodUi", sceneState = KeyguardState.AOD)
// TODO(b/330311871) implement transition to AOD
}
-
- private fun changeToShadeScene() {
- sceneInteractor.changeScene(
- SceneFamilies.NotifShade,
- "ShadeLockscreenInteractorImpl.expandToNotifications",
- )
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
index 77ae679..caa4513 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
@@ -51,6 +51,10 @@
*/
val isShadeLayoutWide: StateFlow<Boolean>
+ /** Convenience shortcut for querying whether the current [shadeMode] is [ShadeMode.Dual]. */
+ val isDualShade: Boolean
+ get() = shadeMode.value is ShadeMode.Dual
+
/**
* The fraction between [0..1] (i.e., percentage) of screen width to consider the threshold
* between "top-left" and "top-right" for the purposes of dual-shade invocation.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
index 0e7beb9d..02a29e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.notification;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -47,6 +47,8 @@
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
+import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.AnimationStateHandler;
import com.android.systemui.statusbar.policy.AvalancheController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpNotificationViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpNotificationViewControllerEmptyImpl.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
index 9f76429..021d301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpNotificationViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone
+package com.android.systemui.statusbar.notification
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper.HeadsUpNotificationViewController
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNotificationViewController
/** Empty impl of [HeadsUpNotificationViewController] for use with Scene Container */
class HeadsUpNotificationViewControllerEmptyImpl : HeadsUpNotificationViewController {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
index 26bd7ac..0927a72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.notification;
import android.content.Context;
import android.os.RemoteException;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index 2b0d2aa..63c9e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.data
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
import dagger.Binds
import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
index 637cadd..920541d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
@@ -44,7 +44,7 @@
viewModel,
clearAllNotifications,
launchNotificationSettings,
- launchNotificationHistory
+ launchNotificationHistory,
)
}
}
@@ -55,21 +55,15 @@
viewModel: FooterViewModel,
clearAllNotifications: View.OnClickListener,
launchNotificationSettings: View.OnClickListener,
- launchNotificationHistory: View.OnClickListener
+ launchNotificationHistory: View.OnClickListener,
) = coroutineScope {
- launch {
- bindClearAllButton(
- footer,
- viewModel,
- clearAllNotifications,
- )
- }
+ launch { bindClearAllButton(footer, viewModel, clearAllNotifications) }
launch {
bindManageOrHistoryButton(
footer,
viewModel,
launchNotificationSettings,
- launchNotificationHistory
+ launchNotificationHistory,
)
}
launch { bindMessage(footer, viewModel) }
@@ -80,8 +74,6 @@
viewModel: FooterViewModel,
clearAllNotifications: View.OnClickListener,
) = coroutineScope {
- footer.setClearAllButtonClickListener(clearAllNotifications)
-
launch {
viewModel.clearAllButton.labelId.collect { textId ->
footer.setClearAllButtonText(textId)
@@ -96,18 +88,21 @@
launch {
viewModel.clearAllButton.isVisible.collect { isVisible ->
+ if (isVisible.value) {
+ footer.setClearAllButtonClickListener(clearAllNotifications)
+ } else {
+ // When the button isn't visible, it also shouldn't react to clicks. This is
+ // necessary because when the clear all button is not visible, it's actually
+ // just the alpha that becomes 0 so it can still be tapped.
+ footer.setClearAllButtonClickListener(null)
+ }
+
if (isVisible.isAnimating) {
- footer.setClearAllButtonVisible(
- isVisible.value,
- /* animate = */ true,
- ) { _ ->
+ footer.setClearAllButtonVisible(isVisible.value, /* animate= */ true) { _ ->
isVisible.stopAnimating()
}
} else {
- footer.setClearAllButtonVisible(
- isVisible.value,
- /* animate = */ false,
- )
+ footer.setClearAllButtonVisible(isVisible.value, /* animate= */ false)
}
}
}
@@ -143,22 +138,24 @@
launch {
viewModel.manageOrHistoryButton.isVisible.collect { isVisible ->
- // NOTE: This visibility change is never animated.
+ // NOTE: This visibility change is never animated. We also don't need to do anything
+ // special about the onClickListener here, since we're changing the visibility to
+ // GONE so it won't be clickable anyway.
footer.setManageOrHistoryButtonVisible(isVisible.value)
}
}
}
- private suspend fun bindMessage(
- footer: FooterView,
- viewModel: FooterViewModel,
- ) = coroutineScope {
- // Bind the resource IDs
- footer.setMessageString(viewModel.message.messageId)
- footer.setMessageIcon(viewModel.message.iconId)
+ private suspend fun bindMessage(footer: FooterView, viewModel: FooterViewModel) =
+ coroutineScope {
+ // Bind the resource IDs
+ footer.setMessageString(viewModel.message.messageId)
+ footer.setMessageIcon(viewModel.message.iconId)
- launch {
- viewModel.message.isVisible.collect { visible -> footer.setFooterLabelVisible(visible) }
+ launch {
+ viewModel.message.isVisible.collect { visible ->
+ footer.setFooterLabelVisible(visible)
+ }
+ }
}
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1214440a..7543f3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -120,7 +120,7 @@
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape;
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index bcdc3bc..e5f63c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -129,9 +129,9 @@
import com.android.systemui.statusbar.notification.shared.GroupHunAnimationFix;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpNotificationViewControllerEmptyImpl;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper.HeadsUpNotificationViewController;
+import com.android.systemui.statusbar.notification.HeadsUpNotificationViewControllerEmptyImpl;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNotificationViewController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 3e42413..8d7007b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState.Idle
import com.android.compose.animation.scene.ObservableTransitionState.Transition
import com.android.compose.animation.scene.ObservableTransitionState.Transition.ChangeScene
@@ -26,7 +27,7 @@
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -46,7 +47,6 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
/** ViewModel which represents the state of the NSSL/Controller in the world of flexiglass */
@@ -91,7 +91,7 @@
): Float {
return if (fullyExpandedDuringSceneChange(change)) {
1f
- } else if (change.isBetween({ it == Scenes.Gone }, { it in SceneFamilies.NotifShade })) {
+ } else if (change.isBetween({ it == Scenes.Gone }, { it == Scenes.Shade })) {
shadeExpansion
} else if (change.isBetween({ it == Scenes.Gone }, { it == Scenes.QuickSettings })) {
// during QS expansion, increase fraction at same rate as scrim alpha,
@@ -99,6 +99,22 @@
(qsExpansion / EXPANSION_FOR_MAX_SCRIM_ALPHA - EXPANSION_FOR_DELAYED_STACK_FADE_IN)
.coerceIn(0f, 1f)
} else {
+ // TODO(b/356596436): If notification shade overlay is open, we'll reach this point and
+ // the expansion fraction in that case should be `shadeExpansion`.
+ 0f
+ }
+ }
+
+ private fun expandFractionDuringOverlayTransition(
+ transition: Transition,
+ currentScene: SceneKey,
+ shadeExpansion: Float,
+ ): Float {
+ return if (currentScene == Scenes.Lockscreen) {
+ 1f
+ } else if (transition.isTransitioningFromOrTo(Overlays.NotificationsShade)) {
+ shadeExpansion
+ } else {
0f
}
}
@@ -114,18 +130,35 @@
shadeInteractor.shadeMode,
shadeInteractor.qsExpansion,
sceneInteractor.transitionState,
- sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
- ) { shadeExpansion, _, qsExpansion, transitionState, _ ->
+ ) { shadeExpansion, _, qsExpansion, transitionState ->
when (transitionState) {
- is Idle -> if (expandedInScene(transitionState.currentScene)) 1f else 0f
+ is Idle ->
+ if (
+ expandedInScene(transitionState.currentScene) ||
+ Overlays.NotificationsShade in transitionState.currentOverlays
+ ) {
+ 1f
+ } else {
+ 0f
+ }
is ChangeScene ->
expandFractionDuringSceneChange(
- transitionState,
- shadeExpansion,
- qsExpansion,
+ change = transitionState,
+ shadeExpansion = shadeExpansion,
+ qsExpansion = qsExpansion,
)
- is Transition.ShowOrHideOverlay,
- is Transition.ReplaceOverlay -> TODO("b/359173565: Handle overlay transitions")
+ is Transition.ShowOrHideOverlay ->
+ expandFractionDuringOverlayTransition(
+ transition = transitionState,
+ currentScene = transitionState.currentScene,
+ shadeExpansion = shadeExpansion,
+ )
+ is Transition.ReplaceOverlay ->
+ expandFractionDuringOverlayTransition(
+ transition = transitionState,
+ currentScene = transitionState.currentScene,
+ shadeExpansion = shadeExpansion,
+ )
}
}
.distinctUntilChanged()
@@ -166,14 +199,14 @@
fun shadeScrimShape(
cornerRadius: Flow<Int>,
- viewLeftOffset: Flow<Int>
+ viewLeftOffset: Flow<Int>,
): Flow<ShadeScrimShape?> =
combine(shadeScrimClipping, cornerRadius, viewLeftOffset) { clipping, radius, leftOffset ->
if (clipping == null) return@combine null
ShadeScrimShape(
bounds = clipping.bounds.minus(leftOffset = leftOffset),
topRadius = radius.takeIf { clipping.rounding.isTopRounded } ?: 0,
- bottomRadius = radius.takeIf { clipping.rounding.isBottomRounded } ?: 0
+ bottomRadius = radius.takeIf { clipping.rounding.isBottomRounded } ?: 0,
)
}
.dumpWhileCollecting("shadeScrimShape")
@@ -209,10 +242,10 @@
/** Whether the notification stack is scrollable or not. */
val isScrollable: Flow<Boolean> =
- sceneInteractor.currentScene
- .map {
- sceneInteractor.isSceneInFamily(it, SceneFamilies.NotifShade) ||
- it == Scenes.Lockscreen
+ combine(sceneInteractor.currentScene, sceneInteractor.currentOverlays) {
+ currentScene,
+ currentOverlays ->
+ currentScene.showsNotifications() || currentOverlays.any { it.showsNotifications() }
}
.dumpWhileCollecting("isScrollable")
@@ -242,13 +275,20 @@
}
}
+ private fun ContentKey.showsNotifications(): Boolean {
+ return when (this) {
+ Overlays.NotificationsShade,
+ Scenes.Lockscreen,
+ Scenes.Shade -> true
+ else -> false
+ }
+ }
+
@AssistedFactory
interface Factory {
fun create(): NotificationScrollViewModel
}
}
-private fun ChangeScene.isBetween(
- a: (SceneKey) -> Boolean,
- b: (SceneKey) -> Boolean,
-): Boolean = (a(fromScene) && b(toScene)) || (b(fromScene) && a(toScene))
+private fun ChangeScene.isBetween(a: (SceneKey) -> Boolean, b: (SceneKey) -> Boolean): Boolean =
+ (a(fromScene) && b(toScene)) || (b(fromScene) && a(toScene))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
index d4ef42c..5b37468 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt
@@ -470,9 +470,6 @@
if (dismissShade) {
shadeControllerLazy.get().collapseShadeForActivityStart()
}
- if (Flags.communalHub()) {
- communalSceneInteractor.changeSceneForActivityStartOnDismissKeyguard()
- }
return deferred
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7227b93..50e9249 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1511,8 +1511,6 @@
mNotificationShadeWindowController.fetchWindowRootView();
getNotificationShadeWindowViewController().setupExpandedStatusBar();
getNotificationShadeWindowViewController().setupCommunalHubLayout();
- mShadeController.setNotificationShadeWindowViewController(
- getNotificationShadeWindowViewController());
mBackActionInteractor.setup(mQsController, mShadeSurface);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
index 0d0f2cd..7919c84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
@@ -1,6 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.systemui.statusbar.phone
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Binds
import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 45aee5b..a658115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -30,6 +30,7 @@
import android.view.WindowInsets;
import androidx.annotation.VisibleForTesting;
+
import com.android.compose.animation.scene.ObservableTransitionState;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dumpable;
@@ -69,7 +70,9 @@
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private boolean mIsStatusBarExpanded = false;
- private boolean mIsIdleOnGone = true;
+ // Whether the scene container has no UI to render, i.e. is in idle state on the Gone scene and
+ // without any overlays to display.
+ private boolean mIsSceneContainerUiEmpty = true;
private boolean mIsRemoteUserInteractionOngoing = false;
private boolean mShouldAdjustInsets = false;
private View mNotificationShadeWindowView;
@@ -134,7 +137,7 @@
if (SceneContainerFlag.isEnabled()) {
javaAdapter.alwaysCollectFlow(
sceneInteractor.get().getTransitionState(),
- this::onSceneChanged);
+ this::onSceneContainerTransition);
javaAdapter.alwaysCollectFlow(
sceneInteractor.get().isRemoteUserInteractionOngoing(),
this::onRemoteUserInteractionOngoingChanged);
@@ -172,11 +175,13 @@
}
}
- private void onSceneChanged(ObservableTransitionState transitionState) {
- boolean isIdleOnGone = transitionState.isIdle(Scenes.Gone);
- if (isIdleOnGone != mIsIdleOnGone) {
- mIsIdleOnGone = isIdleOnGone;
- if (!isIdleOnGone) {
+ private void onSceneContainerTransition(ObservableTransitionState transitionState) {
+ boolean isSceneContainerUiEmpty = transitionState.isIdle(Scenes.Gone)
+ && ((ObservableTransitionState.Idle) transitionState).getCurrentOverlays()
+ .isEmpty();
+ if (isSceneContainerUiEmpty != mIsSceneContainerUiEmpty) {
+ mIsSceneContainerUiEmpty = isSceneContainerUiEmpty;
+ if (!isSceneContainerUiEmpty) {
// make sure our state is sensible
mForceCollapsedUntilLayout = false;
}
@@ -296,7 +301,7 @@
// underneath.
return mIsStatusBarExpanded
|| (SceneContainerFlag.isEnabled()
- && (!mIsIdleOnGone || mIsRemoteUserInteractionOngoing))
+ && (!mIsSceneContainerUiEmpty || mIsRemoteUserInteractionOngoing))
|| mPrimaryBouncerInteractor.isShowing().getValue()
|| mAlternateBouncerInteractor.isVisibleState()
|| mUnlockedScreenOffAnimationController.isAnimationPlaying();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index ca94363..c089092 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -31,7 +31,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.settingslib.bluetooth.BluetoothCallback;
-import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -72,7 +71,6 @@
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
- private final Context mContext;
@GuardedBy("mConnectedDevices")
private final List<CachedBluetoothDevice> mConnectedDevices = new ArrayList<>();
@@ -101,7 +99,6 @@
@Main Looper mainLooper,
@Nullable LocalBluetoothManager localBluetoothManager,
@Nullable BluetoothAdapter bluetoothAdapter) {
- mContext = context;
mDumpManager = dumpManager;
mLogger = logger;
mBluetoothRepository = bluetoothRepository;
@@ -265,21 +262,9 @@
}
private Collection<CachedBluetoothDevice> getDevices() {
- Collection<CachedBluetoothDevice> devices =
- mLocalBluetoothManager != null
- ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
- : Collections.emptyList();
- if (com.android.settingslib.flags.Flags.enableHideExclusivelyManagedBluetoothDevice()) {
- // When the device is exclusively managed by its owner app it needs to be hidden.
- devices =
- devices.stream()
- .filter(
- device ->
- !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
- mContext, device.getDevice()))
- .toList();
- }
- return devices;
+ return mLocalBluetoothManager != null
+ ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
+ : Collections.emptyList();
}
private void updateConnected() {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
index a3b1867..411ff8b 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
@@ -24,8 +24,6 @@
import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureMonitor
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
-import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
@Composable
fun BackGestureTutorialScreen(
@@ -49,14 +47,11 @@
)
)
val gestureMonitorProvider =
- object : GestureMonitorProvider {
- override fun createGestureMonitor(
- gestureDistanceThresholdPx: Int,
- gestureStateChangedCallback: (GestureState) -> Unit
- ): TouchpadGestureMonitor {
- return BackGestureMonitor(gestureDistanceThresholdPx, gestureStateChangedCallback)
+ DistanceBasedGestureMonitorProvider(
+ monitorFactory = { distanceThresholdPx, gestureStateCallback ->
+ BackGestureMonitor(distanceThresholdPx, gestureStateCallback)
}
- }
+ )
GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
index 57d7c84..0ecbf70 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
@@ -16,6 +16,7 @@
package com.android.systemui.touchpad.tutorial.ui.composable
+import android.content.res.Resources
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
@@ -39,12 +40,35 @@
import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
interface GestureMonitorProvider {
- fun createGestureMonitor(
- gestureDistanceThresholdPx: Int,
+
+ @Composable
+ fun rememberGestureMonitor(
+ resources: Resources,
gestureStateChangedCallback: (GestureState) -> Unit
): TouchpadGestureMonitor
}
+typealias gestureStateCallback = (GestureState) -> Unit
+
+class DistanceBasedGestureMonitorProvider(
+ val monitorFactory: (Int, gestureStateCallback) -> TouchpadGestureMonitor
+) : GestureMonitorProvider {
+
+ @Composable
+ override fun rememberGestureMonitor(
+ resources: Resources,
+ gestureStateChangedCallback: (GestureState) -> Unit
+ ): TouchpadGestureMonitor {
+ val distanceThresholdPx =
+ resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_distance_threshold
+ )
+ return remember(distanceThresholdPx) {
+ monitorFactory(distanceThresholdPx, gestureStateChangedCallback)
+ }
+ }
+}
+
fun GestureState.toTutorialActionState(): TutorialActionState {
return when (this) {
NOT_STARTED -> TutorialActionState.NOT_STARTED
@@ -62,19 +86,12 @@
) {
BackHandler(onBack = onBack)
var gestureState by remember { mutableStateOf(NOT_STARTED) }
- val swipeDistanceThresholdPx =
- LocalContext.current.resources.getDimensionPixelSize(
- com.android.internal.R.dimen.system_gestures_distance_threshold
+ val gestureMonitor =
+ gestureMonitorProvider.rememberGestureMonitor(
+ resources = LocalContext.current.resources,
+ gestureStateChangedCallback = { gestureState = it }
)
- val gestureHandler =
- remember(swipeDistanceThresholdPx) {
- TouchpadGestureHandler(
- gestureMonitorProvider.createGestureMonitor(
- swipeDistanceThresholdPx,
- gestureStateChangedCallback = { gestureState = it }
- )
- )
- }
+ val gestureHandler = remember(gestureMonitor) { TouchpadGestureHandler(gestureMonitor) }
TouchpadGesturesHandlingBox(gestureHandler, gestureState) {
ActionTutorialContent(
gestureState.toTutorialActionState(),
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
index d4eb0cd..f2fec5f 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
@@ -23,9 +23,7 @@
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
import com.android.systemui.res.R
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureMonitor
-import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
@Composable
fun HomeGestureTutorialScreen(
@@ -49,14 +47,11 @@
)
)
val gestureMonitorProvider =
- object : GestureMonitorProvider {
- override fun createGestureMonitor(
- gestureDistanceThresholdPx: Int,
- gestureStateChangedCallback: (GestureState) -> Unit
- ): TouchpadGestureMonitor {
- return HomeGestureMonitor(gestureDistanceThresholdPx, gestureStateChangedCallback)
+ DistanceBasedGestureMonitorProvider(
+ monitorFactory = { distanceThresholdPx, gestureStateCallback ->
+ HomeGestureMonitor(distanceThresholdPx, gestureStateCallback)
}
- }
+ )
GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
new file mode 100644
index 0000000..b2fb6cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui.composable
+
+import android.content.res.Resources
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import com.airbnb.lottie.compose.rememberLottieDynamicProperties
+import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
+import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
+import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
+import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureMonitor
+import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
+
+@Composable
+fun RecentAppsGestureTutorialScreen(
+ onDoneButtonClicked: () -> Unit,
+ onBack: () -> Unit,
+) {
+ val screenConfig =
+ TutorialScreenConfig(
+ colors = rememberScreenColors(),
+ strings =
+ TutorialScreenConfig.Strings(
+ titleResId = R.string.touchpad_recent_apps_gesture_action_title,
+ bodyResId = R.string.touchpad_recent_apps_gesture_guidance,
+ titleSuccessResId = R.string.touchpad_recent_apps_gesture_success_title,
+ bodySuccessResId = R.string.touchpad_recent_apps_gesture_success_body
+ ),
+ animations =
+ TutorialScreenConfig.Animations(
+ educationResId = R.raw.trackpad_recent_apps_edu,
+ successResId = R.raw.trackpad_recent_apps_success
+ )
+ )
+ val gestureMonitorProvider =
+ object : GestureMonitorProvider {
+ @Composable
+ override fun rememberGestureMonitor(
+ resources: Resources,
+ gestureStateChangedCallback: (GestureState) -> Unit
+ ): TouchpadGestureMonitor {
+ val distanceThresholdPx =
+ resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_distance_threshold
+ )
+ val velocityThresholdPxPerMs =
+ resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold)
+ return remember(distanceThresholdPx, velocityThresholdPxPerMs) {
+ RecentAppsGestureMonitor(
+ distanceThresholdPx,
+ gestureStateChangedCallback,
+ velocityThresholdPxPerMs
+ )
+ }
+ }
+ }
+ GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
+}
+
+@Composable
+private fun rememberScreenColors(): TutorialScreenConfig.Colors {
+ val secondaryFixedDim = LocalAndroidColorScheme.current.secondaryFixedDim
+ val onSecondaryFixed = LocalAndroidColorScheme.current.onSecondaryFixed
+ val onSecondaryFixedVariant = LocalAndroidColorScheme.current.onSecondaryFixedVariant
+ val dynamicProperties =
+ rememberLottieDynamicProperties(
+ rememberColorFilterProperty(".secondaryFixedDim", secondaryFixedDim),
+ rememberColorFilterProperty(".onSecondaryFixed", onSecondaryFixed),
+ rememberColorFilterProperty(".onSecondaryFixedVariant", onSecondaryFixedVariant)
+ )
+ val screenColors =
+ remember(dynamicProperties) {
+ TutorialScreenConfig.Colors(
+ background = onSecondaryFixed,
+ title = secondaryFixedDim,
+ animationColors = dynamicProperties,
+ )
+ }
+ return screenColors
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 65b452a..5a77c04 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -41,7 +41,7 @@
fun TutorialSelectionScreen(
onBackTutorialClicked: () -> Unit,
onHomeTutorialClicked: () -> Unit,
- onActionKeyTutorialClicked: () -> Unit,
+ onRecentAppsTutorialClicked: () -> Unit,
onDoneButtonClicked: () -> Unit,
) {
Column(
@@ -55,7 +55,7 @@
TutorialSelectionButtons(
onBackTutorialClicked = onBackTutorialClicked,
onHomeTutorialClicked = onHomeTutorialClicked,
- onActionKeyTutorialClicked = onActionKeyTutorialClicked,
+ onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
modifier = Modifier.padding(60.dp)
)
DoneButton(
@@ -69,7 +69,7 @@
private fun TutorialSelectionButtons(
onBackTutorialClicked: () -> Unit,
onHomeTutorialClicked: () -> Unit,
- onActionKeyTutorialClicked: () -> Unit,
+ onRecentAppsTutorialClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Row(
@@ -90,8 +90,8 @@
modifier = Modifier.weight(1f)
)
TutorialButton(
- text = stringResource(R.string.touchpad_tutorial_action_key_button),
- onClick = onActionKeyTutorialClicked,
+ text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button),
+ onClick = onRecentAppsTutorialClicked,
color = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.weight(1f)
)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 821b51a..46ea352 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -32,10 +32,12 @@
import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
+import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.TutorialSelectionScreen
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.ACTION_KEY
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.BACK_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.HOME_GESTURE
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.RECENT_APPS_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.TUTORIAL_SELECTION
import com.android.systemui.touchpad.tutorial.ui.viewmodel.TouchpadTutorialViewModel
import javax.inject.Inject
@@ -84,7 +86,7 @@
TutorialSelectionScreen(
onBackTutorialClicked = { vm.goTo(BACK_GESTURE) },
onHomeTutorialClicked = { vm.goTo(HOME_GESTURE) },
- onActionKeyTutorialClicked = { vm.goTo(ACTION_KEY) },
+ onRecentAppsTutorialClicked = { vm.goTo(RECENT_APPS_GESTURE) },
onDoneButtonClicked = closeTutorial
)
BACK_GESTURE ->
@@ -97,6 +99,11 @@
onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
onBack = { vm.goTo(TUTORIAL_SELECTION) },
)
+ RECENT_APPS_GESTURE ->
+ RecentAppsGestureTutorialScreen(
+ onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
+ onBack = { vm.goTo(TUTORIAL_SELECTION) },
+ )
ACTION_KEY -> // TODO(b/358105049) move action key tutorial to OOBE flow
ActionKeyTutorialScreen(
onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
index 43266ad..599e1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
@@ -64,5 +64,6 @@
TUTORIAL_SELECTION,
BACK_GESTURE,
HOME_GESTURE,
+ RECENT_APPS_GESTURE,
ACTION_KEY,
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 030a20a..079c72f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -539,10 +539,12 @@
!= 0;
changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
} else if (stream == AudioManager.STREAM_VOICE_CALL) {
- final boolean routedToBluetooth =
- (mAudio.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)
- & AudioManager.DEVICE_OUT_BLE_HEADSET) != 0;
- changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
+ final int devices = mAudio.getDevicesForStream(AudioManager.STREAM_VOICE_CALL);
+ final int bluetoothDevicesMask = (AudioManager.DEVICE_OUT_BLE_HEADSET
+ | AudioManager.DEVICE_OUT_BLUETOOTH_SCO_HEADSET
+ | AudioManager.DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ changed |= updateStreamRoutedToBluetoothW(stream,
+ (devices & bluetoothDevicesMask) != 0);
}
return changed;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7786453..db4f9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1991,7 +1991,7 @@
: R.drawable.ic_volume_media_bt;
}
} else if (isStreamMuted(ss)) {
- iconRes = (ss.muted && isTv()) ? R.drawable.ic_volume_media_off : row.iconMuteRes;
+ iconRes = row.iconMuteRes;
} else {
iconRes = mShowLowMediaVolumeIcon && ss.level * 2 < (ss.levelMax + ss.levelMin)
? R.drawable.ic_volume_media_low : row.iconRes;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index c0d8be3..4bb01ec 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -43,6 +43,7 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -96,6 +97,8 @@
private UserActivityNotifier mUserActivityNotifier;
private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController;
private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this);
+ private final BouncerHapticPlayer mBouncerHapticPlayer =
+ mKosmosJavaAdapter.getBouncerHapticHelper();
private final FakeMSDLPlayer mMSDLPlayer = mKosmosJavaAdapter.getMsdlPlayer();
@Before
@@ -119,8 +122,8 @@
return new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector,
- mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor, mMSDLPlayer,
- mUserActivityNotifier) {
+ mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
+ mBouncerHapticPlayer, mUserActivityNotifier) {
@Override
void resetState() {
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 873bc2c..2c1dacd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -35,11 +35,13 @@
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
+import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -107,6 +109,8 @@
@Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
+ private val kosmos = testKosmos()
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -151,8 +155,8 @@
mSelectedUserInteractor,
uiEventLogger,
keyguardKeyboardInteractor,
- null,
- mUserActivityNotifier
+ kosmos.bouncerHapticPlayer,
+ mUserActivityNotifier,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index f141a49..9cd5215 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -28,8 +28,10 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
import com.android.systemui.res.R
+import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
@@ -73,6 +75,8 @@
private val updateMonitorCallbackArgumentCaptor =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ private val kosmos = testKosmos()
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -103,8 +107,8 @@
fakeFeatureFlags,
mSelectedUserInteractor,
keyguardKeyboardInteractor,
- null,
- mUserActivityNotifier
+ kosmos.bouncerHapticPlayer,
+ mUserActivityNotifier,
)
underTest.init()
underTest.onViewAttached()
@@ -162,14 +166,14 @@
updateMonitorCallbackArgumentCaptor.value.onSimStateChanged(
/* subId= */ 0,
/* slotId= */ 0,
- TelephonyManager.SIM_STATE_PIN_REQUIRED
+ TelephonyManager.SIM_STATE_PIN_REQUIRED,
)
verify(keyguardSecurityCallback, never()).showCurrentSecurityScreen()
updateMonitorCallbackArgumentCaptor.value.onSimStateChanged(
/* subId= */ 0,
/* slotId= */ 0,
- TelephonyManager.SIM_STATE_PUK_REQUIRED
+ TelephonyManager.SIM_STATE_PUK_REQUIRED,
)
verify(keyguardSecurityCallback).showCurrentSecurityScreen()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index a03c839..3c22997 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -29,8 +29,10 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
import com.android.systemui.res.R
+import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
import org.junit.Before
@@ -65,6 +67,8 @@
KeyguardMessageAreaController<BouncerKeyguardMessageArea>
@Mock private lateinit var mUserActivityNotifier: UserActivityNotifier
+ private val kosmos = testKosmos()
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -98,8 +102,8 @@
fakeFeatureFlags,
mSelectedUserInteractor,
keyguardKeyboardInteractor,
- null,
- mUserActivityNotifier
+ kosmos.bouncerHapticPlayer,
+ mUserActivityNotifier,
)
underTest.init()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index c451c32..400b3b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -174,6 +174,7 @@
mMenuAnimationController = mMenuView.getMenuAnimationController();
doNothing().when(mSpyContext).startActivity(any());
+ doNothing().when(mSpyContext).startActivityAsUser(any(), any());
when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
mLastAccessibilityButtonTargets =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 76539d7..633efd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -63,21 +63,27 @@
private val defaultDisplay =
display(type = TYPE_INTERNAL, id = DEFAULT_DISPLAY, state = Display.STATE_ON)
- private lateinit var displayRepository: DisplayRepositoryImpl
+ // This is Lazy as displays could be set before the instance is created, and we want to verify
+ // that the initial state (soon after construction) contains the expected ones set in every
+ // test.
+ private val displayRepository: DisplayRepositoryImpl by lazy {
+ DisplayRepositoryImpl(
+ displayManager,
+ testHandler,
+ TestScope(UnconfinedTestDispatcher()),
+ UnconfinedTestDispatcher(),
+ )
+ .also {
+ verify(displayManager, never()).registerDisplayListener(any(), any())
+ // It needs to be called, just once, for the initial value.
+ verify(displayManager).getDisplays()
+ }
+ }
@Before
fun setup() {
setDisplays(listOf(defaultDisplay))
setAllDisplaysIncludingDisabled(DEFAULT_DISPLAY)
- displayRepository =
- DisplayRepositoryImpl(
- displayManager,
- testHandler,
- TestScope(UnconfinedTestDispatcher()),
- UnconfinedTestDispatcher()
- )
- verify(displayManager, never()).registerDisplayListener(any(), any())
- verify(displayManager, never()).getDisplays(any())
}
@Test
@@ -502,7 +508,7 @@
.registerDisplayListener(
connectedDisplayListener.capture(),
eq(testHandler),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED),
)
return flowValue
}
@@ -522,7 +528,7 @@
DisplayManager.EVENT_FLAG_DISPLAY_ADDED or
DisplayManager.EVENT_FLAG_DISPLAY_CHANGED or
DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
- )
+ ),
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index b02cccc..4959224 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -146,9 +146,7 @@
whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
.thenReturn(mock(ResolveInfo::class.java))
- mSetFlagsRule.disableFlags(
- com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
- )
+ mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
subject = createOverviewProxyService(context)
}
@@ -283,6 +281,7 @@
statusBarWinController,
sysUiState,
mock(),
+ mock(),
userTracker,
userManager,
wakefulnessLifecycle,
@@ -294,7 +293,7 @@
dumpManager,
unfoldTransitionProgressForwarder,
broadcastDispatcher,
- keyboardTouchpadEduStatsInteractor
+ keyboardTouchpadEduStatsInteractor,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
index f4d7a5b..d58b68b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -47,7 +47,6 @@
import androidx.test.filters.MediumTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FakeFeatureFlags;
import com.google.common.util.concurrent.ListenableFuture;
@@ -79,7 +78,6 @@
private static final ZonedDateTime CAPTURE_TIME =
ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("America/New_York"));
- private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock
private ContentResolver mMockContentResolver;
@@ -125,7 +123,7 @@
@Test
public void testImageExport() throws ExecutionException, InterruptedException, IOException {
ContentResolver contentResolver = mContext.getContentResolver();
- ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
+ ImageExporter exporter = new ImageExporter(contentResolver);
UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
Bitmap original = createCheckerBitmap(10, 10, 10);
@@ -191,7 +189,7 @@
// metadata are not affected by the specified file name.
final String customizedFileName = "customized_file_name";
ContentResolver contentResolver = mContext.getContentResolver();
- ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
+ ImageExporter exporter = new ImageExporter(contentResolver);
UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
Bitmap original = createCheckerBitmap(10, 10, 10);
@@ -228,7 +226,7 @@
@Test
public void testSetUser() {
- ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
+ ImageExporter exporter = new ImageExporter(mMockContentResolver);
UserHandle imageUserHande = UserHandle.of(10);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
index 886b32b..717f82d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
@@ -31,12 +31,10 @@
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -74,7 +72,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -98,6 +95,10 @@
private static final String BACKLINKS_TASK_APP_NAME = "Ultimate question app";
private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
private static final AssistContent EMPTY_ASSIST_CONTENT = new AssistContent();
+ private static final ResolveInfo BACKLINKS_TASK_RESOLVE_INFO =
+ createBacklinksTaskResolveInfo();
+ private static final RunningTaskInfo BACKLINKS_TASK_RUNNING_TASK_INFO =
+ createTaskInfoForBacklinksTask();
@Mock
private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
@@ -111,26 +112,11 @@
Context mMockedContext;
@Mock
private PackageManager mPackageManager;
- private ArgumentCaptor<Intent> mPackageManagerLauncherIntentCaptor;
- private ArgumentCaptor<Intent> mPackageManagerBacklinkIntentCaptor;
private AppClipsViewModel mViewModel;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
- mPackageManagerLauncherIntentCaptor = ArgumentCaptor.forClass(Intent.class);
- mPackageManagerBacklinkIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-
- // Set up mocking for backlinks.
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(createTaskInfoForBacklinksTask()));
- ResolveInfo expectedResolveInfo = createBacklinksTaskResolveInfo();
- when(mPackageManager.resolveActivity(mPackageManagerLauncherIntentCaptor.capture(),
- anyInt())).thenReturn(expectedResolveInfo);
- when(mPackageManager.queryIntentActivities(mPackageManagerBacklinkIntentCaptor.capture(),
- eq(MATCH_DEFAULT_ONLY))).thenReturn(List.of(expectedResolveInfo));
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
- when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);
mViewModel = new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, mImageExporter,
mAtmService, mAssistContentRequester, mMockedContext,
@@ -208,19 +194,18 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withUri() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withUri() throws RemoteException {
Uri expectedUri = Uri.parse("https://developers.android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
+ mockPackageManagerToResolveUri(expectedUri, BACKLINKS_TASK_RESOLVE_INFO);
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
- Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
- assertThat(queriedIntent.getData()).isEqualTo(expectedUri);
- assertThat(queriedIntent.getAction()).isEqualTo(ACTION_VIEW);
-
BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
@@ -234,14 +219,17 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp()
+ throws RemoteException {
+ // Mock for the screenshotted app so that it can be used for fallback backlink.
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
+ mockBacklinksTaskForMainLauncherIntent();
+
Uri expectedUri = Uri.parse("https://android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
- // Reset PackageManager mocking done in setup.
- reset(mPackageManager);
String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
String appName2 = BACKLINKS_TASK_APP_NAME + 2;
ResolveInfo resolveInfo2 = createBacklinksTaskResolveInfo();
@@ -250,14 +238,9 @@
activityInfo2.packageName = package2;
activityInfo2.applicationInfo.packageName = package2;
- Intent app2LauncherIntent = new Intent(ACTION_MAIN).addCategory(
- CATEGORY_LAUNCHER).setPackage(package2);
- when(mPackageManager.resolveActivity(intentEquals(app2LauncherIntent), eq(/* flags= */ 0)))
- .thenReturn(resolveInfo2);
- Intent uriIntent = new Intent(ACTION_VIEW).setData(expectedUri);
- when(mPackageManager.queryIntentActivities(intentEquals(uriIntent), eq(MATCH_DEFAULT_ONLY)))
- .thenReturn(List.of(resolveInfo2));
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
+ // Mock the different app resolve info so that backlinks resolves to this different app.
+ mockPackageManagerToResolveUri(expectedUri, resolveInfo2);
+ mockPmToResolveForMainLauncherIntent(resolveInfo2);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -273,30 +256,15 @@
assertThat(mViewModel.getBacklinksLiveData().getValue().size()).isEqualTo(1);
}
- private static class IntentMatcher implements ArgumentMatcher<Intent> {
- private final Intent mExpectedIntent;
-
- IntentMatcher(Intent expectedIntent) {
- mExpectedIntent = expectedIntent;
- }
-
- @Override
- public boolean matches(Intent actualIntent) {
- return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
- }
- }
-
- private static Intent intentEquals(Intent intent) {
- return argThat(new IntentMatcher(intent));
- }
-
@Test
- public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent() {
+ public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent()
+ throws RemoteException {
Uri expectedUri = Uri.parse("https://developers.android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
- resetPackageManagerMockingForUsingFallbackBacklinks();
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -305,18 +273,19 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent()
+ throws RemoteException {
Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
AssistContent contentWithAppProvidedIntent = new AssistContent();
contentWithAppProvidedIntent.setIntent(expectedIntent);
mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
+ mockQueryIntentActivities(expectedIntent, BACKLINKS_TASK_RESOLVE_INFO);
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
- Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
- assertThat(queriedIntent.getPackage()).isEqualTo(expectedIntent.getPackage());
-
BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
@@ -328,12 +297,14 @@
}
@Test
- public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent() {
+ public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent()
+ throws RemoteException {
Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
AssistContent contentWithAppProvidedIntent = new AssistContent();
contentWithAppProvidedIntent.setIntent(expectedIntent);
mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
- resetPackageManagerMockingForUsingFallbackBacklinks();
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -342,25 +313,28 @@
}
@Test
- public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent() {
+ public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent()
+ throws RemoteException {
mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+ mockBacklinksTaskForMainLauncherIntent();
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
- Intent queriedIntent = mPackageManagerLauncherIntentCaptor.getValue();
- assertThat(queriedIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
- assertThat(queriedIntent.getAction()).isEqualTo(ACTION_MAIN);
- assertThat(queriedIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
-
verifyMainLauncherBacklinksIntent();
}
@Test
- public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable() {
- reset(mPackageManager);
+ public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable()
+ throws RemoteException {
mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+ // Mock ATM service so we return task info but don't mock PM to resolve the task intent.
+ when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+ false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
+ List.of(BACKLINKS_TASK_RUNNING_TASK_INFO));
+
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -371,11 +345,9 @@
@Test
public void triggerBacklinks_nonStandardActivityIgnored_noBacklinkAvailable()
throws RemoteException {
- reset(mAtmService);
RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(taskInfo));
+ mockAtmToReturnRunningTaskInfo(taskInfo);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -399,9 +371,9 @@
public void triggerBacklinks_multipleAppsOnScreen_multipleBacklinksAvailable()
throws RemoteException {
// Set up mocking for multiple backlinks.
- reset(mAtmService, mPackageManager);
- RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
ResolveInfo resolveInfo1 = createBacklinksTaskResolveInfo();
+ RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
+ runningTaskInfo1.topActivityInfo = resolveInfo1.activityInfo;
int taskId2 = BACKLINKS_TASK_ID + 2;
String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
@@ -418,27 +390,23 @@
runningTaskInfo2.topActivityInfo = resolveInfo2.activityInfo;
runningTaskInfo2.baseIntent = new Intent().setComponent(runningTaskInfo2.topActivity);
- // For each task, the logic queries PM 3 times, twice for verifying if an app can be
- // launched via launcher and once with the data provided in backlink intent.
- when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo1,
- resolveInfo1, resolveInfo2, resolveInfo2);
- when(mPackageManager.queryIntentActivities(any(Intent.class), eq(MATCH_DEFAULT_ONLY)))
- .thenReturn(List.of(resolveInfo1)).thenReturn(List.of(resolveInfo2));
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+ mockAtmToReturnRunningTaskInfo(runningTaskInfo1, runningTaskInfo2);
+ mockPmToResolveForMainLauncherIntent(resolveInfo1);
+ mockPmToResolveForMainLauncherIntent(resolveInfo2);
// Using app provided web uri for the first backlink.
Uri expectedUri = Uri.parse("https://developers.android.com");
AssistContent contentWithUri = new AssistContent();
contentWithUri.setWebUri(expectedUri);
mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
+ mockPackageManagerToResolveUri(expectedUri, resolveInfo1);
// Using app provided intent for the second backlink.
Intent expectedIntent = new Intent().setPackage(package2);
AssistContent contentWithAppProvidedIntent = new AssistContent();
contentWithAppProvidedIntent.setIntent(expectedIntent);
mockForAssistContent(contentWithAppProvidedIntent, taskId2);
+ mockQueryIntentActivities(expectedIntent, resolveInfo2);
// Set up complete, trigger the backlinks action.
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -460,11 +428,12 @@
@Test
public void triggerBacklinks_singleCrossProfileApp_shouldIndicateError()
throws RemoteException {
- reset(mAtmService);
RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
taskInfo.userId = UserHandle.myUserId() + 1;
- when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
- .thenReturn(List.of(taskInfo));
+ when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+ false, /* keepIntentExtra */ false, DEFAULT_DISPLAY)).thenReturn(List.of(taskInfo));
+ when(mPackageManager.loadItemIcon(taskInfo.topActivityInfo,
+ taskInfo.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -478,13 +447,13 @@
throws RemoteException {
// Set up mocking for multiple backlinks.
mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
- reset(mAtmService);
- RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
runningTaskInfo2.userId = UserHandle.myUserId() + 1;
- when(mAtmService.getTasks(anyInt(), anyBoolean(), anyBoolean(), anyInt()))
- .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+ mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO, runningTaskInfo2);
+ when(mPackageManager.loadItemIcon(runningTaskInfo2.topActivityInfo,
+ runningTaskInfo2.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
+ mockBacklinksTaskForMainLauncherIntent();
// Set up complete, trigger the backlinks action.
mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -497,22 +466,6 @@
assertThat(actualBacklinks.get(1)).isInstanceOf(CrossProfileError.class);
}
- private void resetPackageManagerMockingForUsingFallbackBacklinks() {
- ResolveInfo backlinksTaskResolveInfo = createBacklinksTaskResolveInfo();
- reset(mPackageManager);
- when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
- when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
- // Firstly, the logic queries whether a package has a launcher activity, this should
- // resolve otherwise the logic filters out the task.
- .thenReturn(backlinksTaskResolveInfo)
- // Secondly, the logic builds a fallback main launcher intent, this should also
- // resolve for the fallback intent to build correctly.
- .thenReturn(backlinksTaskResolveInfo)
- // Lastly, logic queries with the backlinks intent, this should not resolve for the
- // logic to use the fallback intent.
- .thenReturn(null);
- }
-
private void verifyMainLauncherBacklinksIntent() {
BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
@@ -540,6 +493,59 @@
}).when(mAssistContentRequester).requestAssistContent(eq(taskId), any());
}
+ private void mockPackageManagerToResolveUri(Uri uriToResolve, ResolveInfo resolveInfoToReturn) {
+ Intent uriIntent = new Intent(ACTION_VIEW).setData(uriToResolve);
+ mockQueryIntentActivities(uriIntent, resolveInfoToReturn);
+ mockPmToLoadAppIcon(resolveInfoToReturn);
+ }
+
+ private void mockQueryIntentActivities(Intent expectedIntent, ResolveInfo resolveInfoToReturn) {
+ when(mPackageManager.queryIntentActivities(intentEquals(expectedIntent),
+ eq(MATCH_DEFAULT_ONLY)))
+ .thenReturn(List.of(resolveInfoToReturn));
+ }
+
+ private void mockBacklinksTaskForMainLauncherIntent() {
+ mockPmToResolveForMainLauncherIntent(BACKLINKS_TASK_RESOLVE_INFO);
+ }
+
+ private void mockPmToResolveForMainLauncherIntent(ResolveInfo resolveInfo) {
+ Intent intent = new Intent(ACTION_MAIN).addCategory(CATEGORY_LAUNCHER).setPackage(
+ resolveInfo.activityInfo.packageName);
+ when(mPackageManager.resolveActivity(intentEquals(intent), eq(/* flags= */ 0))).thenReturn(
+ resolveInfo);
+ mockPmToLoadAppIcon(resolveInfo);
+ }
+
+ private void mockPmToLoadAppIcon(ResolveInfo resolveInfo) {
+ when(mPackageManager.loadItemIcon(resolveInfo.activityInfo,
+ resolveInfo.activityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
+ }
+
+ private void mockAtmToReturnRunningTaskInfo(RunningTaskInfo... taskInfos)
+ throws RemoteException {
+ when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+ false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
+ List.of(taskInfos));
+ }
+
+ private static Intent intentEquals(Intent intent) {
+ return argThat(new IntentMatcher(intent));
+ }
+
+ private static class IntentMatcher implements ArgumentMatcher<Intent> {
+ private final Intent mExpectedIntent;
+
+ IntentMatcher(Intent expectedIntent) {
+ mExpectedIntent = expectedIntent;
+ }
+
+ @Override
+ public boolean matches(Intent actualIntent) {
+ return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
+ }
+ }
+
private static ResolveInfo createBacklinksTaskResolveInfo() {
ActivityInfo activityInfo = new ActivityInfo();
activityInfo.applicationInfo = new ApplicationInfo();
@@ -558,7 +564,7 @@
taskInfo.isRunning = true;
taskInfo.numActivities = 1;
taskInfo.topActivity = new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, "backlinksClass");
- taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
+ taskInfo.topActivityInfo = BACKLINKS_TASK_RESOLVE_INFO.activityInfo;
taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
taskInfo.userId = UserHandle.myUserId();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index e0c4ab7..4bd0c75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -167,7 +167,7 @@
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 0217238..905301e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -117,11 +117,11 @@
deviceProvisionedController,
notificationShadeWindowController,
0,
+ Lazy { nswvc },
Lazy { npvc },
Lazy { assistManager },
Lazy { gutsManager },
)
- shadeController.setNotificationShadeWindowViewController(nswvc)
shadeController.setVisibilityListener(mock())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 0846ced..fc2ad60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -244,23 +244,23 @@
}
@Test
- fun dualCarrier_disablesCarrierIconsInStatusIcons() {
+ fun dualCarrier_disablesCarrierIconsInStatusIcons_qs() {
whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false)
makeShadeVisible()
shadeHeaderController.qsExpandedFraction = 1.0f
- verify(statusIcons).addIgnoredSlots(carrierIconSlots)
+ verify(statusIcons, times(2)).addIgnoredSlots(carrierIconSlots)
}
@Test
- fun dualCarrier_enablesCarrierIconsInStatusIcons_qsExpanded() {
+ fun dualCarrier_disablesCarrierIconsInStatusIcons_qqs() {
whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false)
makeShadeVisible()
shadeHeaderController.qsExpandedFraction = 0.0f
- verify(statusIcons, times(2)).removeIgnoredSlots(carrierIconSlots)
+ verify(statusIcons, times(2)).addIgnoredSlots(carrierIconSlots)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index b65a902..a1750cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.shade.domain.interactor
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
@@ -27,16 +29,18 @@
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.testKosmos
-import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,7 +57,12 @@
private val sceneInteractor = kosmos.sceneInteractor
private val shadeTestUtil = kosmos.shadeTestUtil
- private val underTest = kosmos.shadeInteractorSceneContainerImpl
+ private lateinit var underTest: ShadeInteractorSceneContainerImpl
+
+ @Before
+ fun setUp() {
+ underTest = kosmos.shadeInteractorSceneContainerImpl
+ }
@Test
fun qsExpansionWhenInSplitShadeAndQsExpanded() =
@@ -80,7 +89,7 @@
keyguardRepository.setStatusBarState(StatusBarState.SHADE)
// THEN legacy shade expansion is passed through
- Truth.assertThat(actual).isEqualTo(.3f)
+ assertThat(actual).isEqualTo(.3f)
}
@Test
@@ -109,7 +118,7 @@
runCurrent()
// THEN shade expansion is zero
- Truth.assertThat(actual).isEqualTo(.7f)
+ assertThat(actual).isEqualTo(.7f)
}
@Test
@@ -134,7 +143,7 @@
runCurrent()
// THEN QS is not fullscreen
- Truth.assertThat(actual).isFalse()
+ assertThat(actual).isFalse()
}
@Test
@@ -152,7 +161,7 @@
runCurrent()
// THEN QS is not fullscreen
- Truth.assertThat(actual).isFalse()
+ assertThat(actual).isFalse()
}
@Test
@@ -171,7 +180,7 @@
runCurrent()
// THEN QS is not fullscreen
- Truth.assertThat(actual).isFalse()
+ assertThat(actual).isFalse()
}
@Test
@@ -189,7 +198,7 @@
runCurrent()
// THEN QS is fullscreen
- Truth.assertThat(actual).isTrue()
+ assertThat(actual).isTrue()
}
@Test
@@ -206,7 +215,7 @@
sceneInteractor.setTransitionState(transitionState)
// THEN expansion is 1
- Truth.assertThat(expansionAmount).isEqualTo(1f)
+ assertThat(expansionAmount).isEqualTo(1f)
}
@Test
@@ -224,7 +233,7 @@
sceneInteractor.setTransitionState(transitionState)
// THEN expansion is 0
- Truth.assertThat(expansionAmount).isEqualTo(0f)
+ assertThat(expansionAmount).isEqualTo(0f)
}
@Test
@@ -251,19 +260,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN expansion is 0
- Truth.assertThat(expansionAmount).isEqualTo(0f)
+ assertThat(expansionAmount).isEqualTo(0f)
// WHEN transition state is partially to the scene
progress.value = .4f
// THEN expansion matches the progress
- Truth.assertThat(expansionAmount).isEqualTo(.4f)
+ assertThat(expansionAmount).isEqualTo(.4f)
// WHEN transition completes
progress.value = 1f
// THEN expansion is 1
- Truth.assertThat(expansionAmount).isEqualTo(1f)
+ assertThat(expansionAmount).isEqualTo(1f)
}
@Test
@@ -290,19 +299,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN expansion is 1
- Truth.assertThat(expansionAmount).isEqualTo(1f)
+ assertThat(expansionAmount).isEqualTo(1f)
// WHEN transition state is partially to the scene
progress.value = .4f
// THEN expansion reflects the progress
- Truth.assertThat(expansionAmount).isEqualTo(.6f)
+ assertThat(expansionAmount).isEqualTo(.6f)
// WHEN transition completes
progress.value = 1f
// THEN expansion is 0
- Truth.assertThat(expansionAmount).isEqualTo(0f)
+ assertThat(expansionAmount).isEqualTo(0f)
}
fun isQsBypassingShade_goneToQs() =
@@ -326,7 +335,7 @@
runCurrent()
// THEN qs is bypassing shade
- Truth.assertThat(actual).isTrue()
+ assertThat(actual).isTrue()
}
fun isQsBypassingShade_shadeToQs() =
@@ -350,7 +359,7 @@
runCurrent()
// THEN qs is not bypassing shade
- Truth.assertThat(actual).isFalse()
+ assertThat(actual).isFalse()
}
@Test
@@ -376,19 +385,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN expansion is 0
- Truth.assertThat(expansionAmount).isEqualTo(0f)
+ assertThat(expansionAmount).isEqualTo(0f)
// WHEN transition state is partially complete
progress.value = .4f
// THEN expansion is still 0
- Truth.assertThat(expansionAmount).isEqualTo(0f)
+ assertThat(expansionAmount).isEqualTo(0f)
// WHEN transition completes
progress.value = 1f
// THEN expansion is still 0
- Truth.assertThat(expansionAmount).isEqualTo(0f)
+ assertThat(expansionAmount).isEqualTo(0f)
}
@Test
@@ -405,7 +414,7 @@
sceneInteractor.setTransitionState(transitionState)
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
}
@Test
@@ -432,19 +441,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
// WHEN transition state is partially to the scene
progress.value = .4f
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
// WHEN transition completes
progress.value = 1f
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
}
@Test
@@ -471,19 +480,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN interacting is true
- Truth.assertThat(interacting).isTrue()
+ assertThat(interacting).isTrue()
// WHEN transition state is partially to the scene
progress.value = .4f
// THEN interacting is true
- Truth.assertThat(interacting).isTrue()
+ assertThat(interacting).isTrue()
// WHEN transition completes
progress.value = 1f
// THEN interacting is true
- Truth.assertThat(interacting).isTrue()
+ assertThat(interacting).isTrue()
}
@Test
@@ -510,19 +519,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
// WHEN transition state is partially to the scene
progress.value = .4f
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
// WHEN transition completes
progress.value = 1f
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
+ assertThat(interacting).isFalse()
}
@Test
@@ -549,19 +558,19 @@
sceneInteractor.setTransitionState(transitionState)
// THEN interacting is true
- Truth.assertThat(interacting).isTrue()
+ assertThat(interacting).isTrue()
// WHEN transition state is partially to the scene
progress.value = .4f
// THEN interacting is true
- Truth.assertThat(interacting).isTrue()
+ assertThat(interacting).isTrue()
// WHEN transition completes
progress.value = 1f
// THEN interacting is true
- Truth.assertThat(interacting).isTrue()
+ assertThat(interacting).isTrue()
}
@Test
@@ -572,7 +581,6 @@
val interacting by collectLastValue(interactingFlow)
// WHEN transition state is starting to between different scenes
- val progress = MutableStateFlow(0f)
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Transition(
@@ -589,4 +597,94 @@
// THEN interacting is false
assertThat(interacting).isFalse()
}
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun expandNotificationShade_dualShadeEnabled_opensOverlay() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).isEmpty()
+
+ underTest.expandNotificationShade("reason")
+
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun expandNotificationShade_dualShadeDisabled_switchesToShadeScene() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).isEmpty()
+
+ underTest.expandNotificationShade("reason")
+
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
+ assertThat(currentOverlays).isEmpty()
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun expandNotificationShade_dualShadeEnabledAndQuickSettingsOpen_replacesOverlay() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ underTest.expandQuickSettingsShade("reason")
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
+
+ underTest.expandNotificationShade("reason")
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun expandQuickSettingsShade_dualShadeEnabled_opensOverlay() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).isEmpty()
+
+ underTest.expandQuickSettingsShade("reason")
+
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun expandQuickSettingsShade_dualShadeDisabled_switchesToQuickSettingsScene() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).isEmpty()
+
+ underTest.expandQuickSettingsShade("reason")
+
+ assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
+ assertThat(currentOverlays).isEmpty()
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun expandQuickSettingsShade_dualShadeEnabledAndNotificationsOpen_replacesOverlay() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ underTest.expandNotificationShade("reason")
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
+
+ underTest.expandQuickSettingsShade("reason")
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index b4f4138..76bb8de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -43,7 +43,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import com.android.systemui.util.concurrency.FakeExecutor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 3df4a67..30556be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -103,7 +103,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c7c08a9..af04309 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -467,13 +467,12 @@
mDeviceProvisionedController,
mNotificationShadeWindowController,
0,
+ () -> mNotificationShadeWindowViewController,
() -> mNotificationPanelViewController,
() -> mAssistManager,
() -> mNotificationGutsManager
));
}
- mShadeController.setNotificationShadeWindowViewController(
- mNotificationShadeWindowViewController);
mShadeController.setNotificationPresenter(mNotificationPresenter);
when(mOperatorNameViewControllerFactory.create(any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 93071bd..2588f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -14,10 +14,6 @@
package com.android.systemui.statusbar.policy;
-import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf;
-
-import static com.android.settingslib.flags.Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -25,7 +21,6 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -35,11 +30,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.FlagsParameterization;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -65,31 +56,16 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
-@RunWith(ParameterizedAndroidJunit4.class)
+@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
public class BluetoothControllerImplTest extends SysuiTestCase {
- @Parameters(name = "{0}")
- public static List<FlagsParameterization> getParams() {
- return allCombinationsOf(FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE);
- }
-
- private static final String TEST_EXCLUSIVE_MANAGER = "com.test.manager";
-
- @Mock
- private PackageManager mPackageManager;
-
private UserTracker mUserTracker;
private LocalBluetoothManager mMockBluetoothManager;
private CachedBluetoothDeviceManager mMockDeviceManager;
@@ -102,21 +78,14 @@
private FakeExecutor mBackgroundExecutor;
- public BluetoothControllerImplTest(FlagsParameterization flags) {
- super();
- mSetFlagsRule.setFlagsParameterization(flags);
- }
-
@Before
public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
mMockBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager.class);
mDevices = new ArrayList<>();
mUserTracker = mock(UserTracker.class);
mMockDeviceManager = mock(CachedBluetoothDeviceManager.class);
mMockAdapter = mock(BluetoothAdapter.class);
- mContext.setMockPackageManager(mPackageManager);
when(mMockDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
when(mMockBluetoothManager.getCachedDeviceManager()).thenReturn(mMockDeviceManager);
mMockLocalAdapter = mock(LocalBluetoothAdapter.class);
@@ -146,7 +115,6 @@
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
when(device.isConnected()).thenReturn(true);
when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
- when(device.getDevice()).thenReturn(mock(BluetoothDevice.class));
mDevices.add(device);
when(mMockLocalAdapter.getConnectionState())
@@ -172,12 +140,10 @@
public void getConnectedDevices_onlyReturnsConnected() {
CachedBluetoothDevice device1Disconnected = mock(CachedBluetoothDevice.class);
when(device1Disconnected.isConnected()).thenReturn(false);
- when(device1Disconnected.getDevice()).thenReturn(mock(BluetoothDevice.class));
mDevices.add(device1Disconnected);
CachedBluetoothDevice device2Connected = mock(CachedBluetoothDevice.class);
when(device2Connected.isConnected()).thenReturn(true);
- when(device2Connected.getDevice()).thenReturn(mock(BluetoothDevice.class));
mDevices.add(device2Connected);
mBluetoothControllerImpl.onDeviceAdded(device1Disconnected);
@@ -189,46 +155,6 @@
}
@Test
- @EnableFlags(FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- public void getConnectedDevice_exclusivelyManagedDevice_doNotReturn()
- throws PackageManager.NameNotFoundException {
- CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
- when(cachedDevice.isConnected()).thenReturn(true);
- BluetoothDevice device = mock(BluetoothDevice.class);
- when(device.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
- TEST_EXCLUSIVE_MANAGER.getBytes());
- when(cachedDevice.getDevice()).thenReturn(device);
- doReturn(new ApplicationInfo()).when(mPackageManager).getApplicationInfo(
- TEST_EXCLUSIVE_MANAGER, 0);
-
- mDevices.add(cachedDevice);
- mBluetoothControllerImpl.onDeviceAdded(cachedDevice);
-
- assertThat(mBluetoothControllerImpl.getConnectedDevices()).isEmpty();
- }
-
- @Test
- @DisableFlags(FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
- public void getConnectedDevice_exclusivelyManagedDevice_returnsConnected()
- throws PackageManager.NameNotFoundException {
- CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
- when(cachedDevice.isConnected()).thenReturn(true);
- BluetoothDevice device = mock(BluetoothDevice.class);
- when(device.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
- TEST_EXCLUSIVE_MANAGER.getBytes());
- when(cachedDevice.getDevice()).thenReturn(device);
- doReturn(new ApplicationInfo()).when(mPackageManager).getApplicationInfo(
- TEST_EXCLUSIVE_MANAGER, 0);
-
- mDevices.add(cachedDevice);
- mBluetoothControllerImpl.onDeviceAdded(cachedDevice);
-
- assertThat(mBluetoothControllerImpl.getConnectedDevices()).hasSize(1);
- assertThat(mBluetoothControllerImpl.getConnectedDevices().get(0))
- .isEqualTo(cachedDevice);
- }
-
- @Test
public void testOnBluetoothStateChange_updatesBluetoothState() {
mBluetoothControllerImpl.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
@@ -259,7 +185,6 @@
assertFalse(mBluetoothControllerImpl.isBluetoothConnected());
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
- when(device.getDevice()).thenReturn(mock(BluetoothDevice.class));
mDevices.add(device);
when(device.isConnected()).thenReturn(true);
when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -478,7 +403,6 @@
private CachedBluetoothDevice createBluetoothDevice(
int profile, boolean isConnected, boolean isActive) {
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
- when(device.getDevice()).thenReturn(mock(BluetoothDevice.class));
mDevices.add(device);
when(device.isActiveDevice(profile)).thenReturn(isActive);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
index cafebb9..d059c14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
@@ -38,8 +38,7 @@
companion object {
const val THRESHOLD_VELOCITY_PX_PER_MS = 0.1f
- // multiply by 1000 to get px per ms instead of px per s which is unit used by velocity
- // tracker
+ // multiply by 1000 to get px/ms instead of px/s which is unit used by velocity tracker
const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS * 1000 - 1
const val FAST = THRESHOLD_VELOCITY_PX_PER_MS * 1000 + 1
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index f5bcc21..feee0a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -38,6 +38,7 @@
import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.inOrder
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@@ -79,6 +80,26 @@
}
@Test
+ fun onRotationChanged_rotationSentMultipleWithTheSameValue_listenerReceivesUpdateOnce() {
+ sendRotationUpdate(42)
+ sendRotationUpdate(42)
+ sendRotationUpdate(42)
+
+ verify(listener).onRotationChanged(42)
+ }
+
+ @Test
+ fun onRotationChanged_rotationSentMultipleTimesWithDifferentValues_listenerReceivesUpdates() {
+ sendRotationUpdate(0)
+ sendRotationUpdate(1)
+
+ with(inOrder(listener)) {
+ verify(listener).onRotationChanged(0)
+ verify(listener).onRotationChanged(1)
+ }
+ }
+
+ @Test
fun onRotationChanged_subscribersRemoved_noRotationChangeReceived() {
sendRotationUpdate(42)
verify(listener).onRotationChanged(42)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt
index d31491d..25c4bbb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt
@@ -18,4 +18,6 @@
import com.android.systemui.kosmos.Kosmos
-var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { FalsingCollectorFake() }
+var Kosmos.fakeFalsingCollector by Kosmos.Fixture { FalsingCollectorFake() }
+
+var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { fakeFalsingCollector }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorKosmos.kt
index 2ab8221..209d163 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.communal.shared.log.communalSceneLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
val Kosmos.communalSceneInteractor: CommunalSceneInteractor by
Kosmos.Fixture {
@@ -27,5 +28,6 @@
applicationScope = applicationCoroutineScope,
repository = communalSceneRepository,
logger = communalSceneLogger,
+ sceneInteractor = sceneInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
index 13116e7..096022c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.keyguard.dismissCallbackRegistry
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -36,5 +37,6 @@
deviceUnlockedInteractor = deviceUnlockedInteractor,
alternateBouncerInteractor = alternateBouncerInteractor,
dismissCallbackRegistry = dismissCallbackRegistry,
+ sceneBackInteractor = sceneBackInteractor,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt
similarity index 60%
copy from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt
index 48ec198..94982ed 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.scene.ui.composable.transitions
+package com.android.systemui.haptics.msdl
-import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer
+import com.android.systemui.kosmos.Kosmos
+import com.google.android.msdl.domain.MSDLPlayer
+import dagger.Lazy
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
-}
+val Kosmos.bouncerHapticPlayer: BouncerHapticPlayer by
+ Kosmos.Fixture {
+ val lazyPlayer = Lazy<MSDLPlayer> { fakeMSDLPlayer }
+ BouncerHapticPlayer(lazyPlayer)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
index d920c4f..574bbcd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
@@ -17,14 +17,12 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
import com.android.systemui.shade.domain.interactor.shadeInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -37,12 +35,9 @@
dismissInteractor = keyguardDismissInteractor,
applicationScope = testScope.backgroundScope,
sceneInteractor = { sceneInteractor },
- deviceEntryInteractor = { deviceEntryInteractor },
- quickSettingsSceneFamilyResolver = { quickSettingsSceneFamilyResolver },
- notifShadeSceneFamilyResolver = { notifShadeSceneFamilyResolver },
+ deviceUnlockedInteractor = { deviceUnlockedInteractor },
powerInteractor = powerInteractor,
alternateBouncerInteractor = alternateBouncerInteractor,
- keyguardInteractor = { keyguardInteractor },
shadeInteractor = { shadeInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index c60305e..f97f303 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -36,6 +36,7 @@
import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.globalactions.domain.interactor.globalActionsInteractor
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
import com.android.systemui.haptics.msdl.fakeMSDLPlayer
import com.android.systemui.haptics.qs.qsLongPressEffect
import com.android.systemui.jank.interactionJankMonitor
@@ -158,4 +159,5 @@
val sceneContainerOcclusionInteractor by lazy { kosmos.sceneContainerOcclusionInteractor }
val msdlPlayer by lazy { kosmos.fakeMSDLPlayer }
val shadeModeInteractor by lazy { kosmos.shadeModeInteractor }
+ val bouncerHapticHelper by lazy { kosmos.bouncerHapticPlayer }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt
index 8fc40e4..6ced8c3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt
@@ -18,8 +18,12 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.fakeQsSceneAdapter: FakeQSSceneAdapter by Fixture { FakeQSSceneAdapter({ mock() }) }
val Kosmos.quickSettingsShadeOverlayActionsViewModel:
QuickSettingsShadeOverlayActionsViewModel by Fixture {
- QuickSettingsShadeOverlayActionsViewModel()
+ QuickSettingsShadeOverlayActionsViewModel(quickSettingsContainerViewModel)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
index d17b575..8b12425 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
@@ -24,16 +24,10 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver>
- get() =
- mapOf(
- SceneFamilies.Home to homeSceneFamilyResolver,
- SceneFamilies.NotifShade to notifShadeSceneFamilyResolver,
- SceneFamilies.QuickSettings to quickSettingsSceneFamilyResolver,
- )
+ get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver)
val Kosmos.homeSceneFamilyResolver by
Kosmos.Fixture {
@@ -43,19 +37,3 @@
keyguardEnabledInteractor = keyguardEnabledInteractor,
)
}
-
-val Kosmos.notifShadeSceneFamilyResolver by
- Kosmos.Fixture {
- NotifShadeSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- shadeModeInteractor = shadeModeInteractor,
- )
- }
-
-val Kosmos.quickSettingsSceneFamilyResolver by
- Kosmos.Fixture {
- QuickSettingsSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- shadeModeInteractor = shadeModeInteractor,
- )
- }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
index 9a5698c..4228c3c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
@@ -32,13 +32,11 @@
import com.android.systemui.keyguard.dismissCallbackRegistry
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
-import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
@@ -62,7 +60,6 @@
deviceUnlockedInteractor = deviceUnlockedInteractor,
bouncerInteractor = bouncerInteractor,
keyguardInteractor = keyguardInteractor,
- keyguardTransitionInteractor = keyguardTransitionInteractor,
sysUiState = sysUiState,
displayId = displayTracker.defaultDisplayId,
sceneLogger = sceneLogger,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index 0bc4d54..ddcc6d6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -71,6 +71,7 @@
deviceProvisionedController,
mock<NotificationShadeWindowController>(),
0,
+ { mock<NotificationShadeWindowViewController>() },
{ mock<NotificationPanelViewController>() },
{ mock<AssistManager>() },
{ mock<NotificationGutsManager>() },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 04d930c..92075ea 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -44,7 +44,7 @@
ShadeInteractorSceneContainerImpl(
scope = applicationCoroutineScope,
sceneInteractor = sceneInteractor,
- shadeRepository = shadeRepository,
+ shadeModeInteractor = shadeModeInteractor,
)
}
val Kosmos.shadeInteractorLegacyImpl by
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/TestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/TestUtils.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/TestUtils.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/util/TestUtils.kt
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 0458f53..b1e6fe2 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -103,7 +103,7 @@
if (displayId == display.displayId) {
val currentRotation = display.rotation
- if (lastRotation.compareAndSet(lastRotation.get(), currentRotation)) {
+ if (lastRotation.getAndSet(currentRotation) != currentRotation) {
listeners.forEach { it.onRotationChanged(currentRotation) }
}
}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 136738f..acb74d3 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -1620,7 +1620,7 @@
}
ret.outputConfigs.add(entry);
}
- if (Flags.extension10Bit() && EFV_SUPPORTED) {
+ if (EFV_SUPPORTED) {
ret.colorSpace = sessionConfig.getColorSpace();
} else {
ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
@@ -2596,7 +2596,7 @@
private static CameraOutputConfig getCameraOutputConfig(Camera2OutputConfigImpl output) {
CameraOutputConfig ret = new CameraOutputConfig();
- if (Flags.extension10Bit() && EFV_SUPPORTED) {
+ if (EFV_SUPPORTED) {
ret.dynamicRangeProfile = output.getDynamicRangeProfile();
} else {
ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 3c65f37..d1a3bf9 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -5,6 +5,10 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+
+ // OWNER: g/ravenwood
+ // Bug component: 25698
+ default_team: "trendy_team_framework_backstage_power",
}
filegroup {
@@ -337,8 +341,8 @@
android_ravenwood_libgroup {
name: "ravenwood-runtime",
data: [
- "framework-res",
- "ravenwood-empty-res",
+ ":framework-res",
+ ":ravenwood-empty-res",
],
libs: [
"100-framework-minus-apex.ravenwood",
diff --git a/ravenwood/OWNERS b/ravenwood/OWNERS
index f7b13d1..8722ad9 100644
--- a/ravenwood/OWNERS
+++ b/ravenwood/OWNERS
@@ -1,5 +1,7 @@
+# Bug component: 25698
set noparent
+omakoto@google.com
topjohnwu@google.com
hackbod@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING
index 7f9d9c2..f9b5d2c 100644
--- a/ravenwood/TEST_MAPPING
+++ b/ravenwood/TEST_MAPPING
@@ -7,6 +7,9 @@
{ "name": "RavenwoodMockitoTest_device" },
{ "name": "RavenwoodBivalentTest_device" },
+ { "name": "RavenwoodBivalentInstTest_nonself_inst" },
+ { "name": "RavenwoodBivalentInstTest_self_inst_device" },
+
// The sysui tests should match vendor/unbundled_google/packages/SystemUIGoogle/TEST_MAPPING
{
"name": "SystemUIGoogleTests",
@@ -138,6 +141,14 @@
"host": true
},
{
+ "name": "RavenwoodBivalentInstTest_nonself_inst",
+ "host": true
+ },
+ {
+ "name": "RavenwoodBivalentInstTest_self_inst",
+ "host": true
+ },
+ {
"name": "RavenwoodBivalentTest",
"host": true
},
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
index 68472c1..7a6f9e3 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
@@ -108,7 +108,7 @@
Log.v(TAG, "onBeforeInnerRunnerStart: description=" + description);
// Prepare the environment before the inner runner starts.
- RavenwoodRunnerState.forRunner(runner).enterTestClass(description);
+ runner.mState.enterTestClass(description);
}
/**
@@ -119,7 +119,7 @@
Log.v(TAG, "onAfterInnerRunnerFinished: description=" + description);
RavenwoodTestStats.getInstance().onClassFinished(description);
- RavenwoodRunnerState.forRunner(runner).exitTestClass();
+ runner.mState.exitTestClass();
}
/**
@@ -133,10 +133,10 @@
if (scope == Scope.Instance && order == Order.Outer) {
// Start of a test method.
- RavenwoodRunnerState.forRunner(runner).enterTestMethod(description);
+ runner.mState.enterTestMethod(description);
}
- final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
+ final var classDescription = runner.mState.getClassDescription();
// Class-level annotations are checked by the runner already, so we only check
// method-level annotations here.
@@ -160,11 +160,11 @@
Scope scope, Order order, Throwable th) {
Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th);
- final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
+ final var classDescription = runner.mState.getClassDescription();
if (scope == Scope.Instance && order == Order.Outer) {
// End of a test method.
- RavenwoodRunnerState.forRunner(runner).exitTestMethod();
+ runner.mState.exitTestMethod();
RavenwoodTestStats.getInstance().onTestFinished(classDescription, description,
th == null ? Result.Passed : Result.Failed);
}
@@ -214,7 +214,7 @@
Description description, RavenwoodRule rule) throws Throwable {
Log.v(TAG, "onRavenwoodRuleEnter: description=" + description);
- RavenwoodRunnerState.forRunner(runner).enterRavenwoodRule(rule);
+ runner.mState.enterRavenwoodRule(rule);
}
@@ -225,6 +225,6 @@
Description description, RavenwoodRule rule) throws Throwable {
Log.v(TAG, "onRavenwoodRuleExit: description=" + description);
- RavenwoodRunnerState.forRunner(runner).exitRavenwoodRule(rule);
+ runner.mState.exitRavenwoodRule(rule);
}
}
\ No newline at end of file
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
new file mode 100644
index 0000000..3535cb2
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood;
+
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.app.ResourcesManager;
+import android.content.res.Resources;
+import android.view.DisplayAdjustments;
+
+import java.io.File;
+import java.util.HashMap;
+
+/**
+ * Used to store various states associated with {@link RavenwoodConfig} that's inly needed
+ * in junit-impl.
+ *
+ * We don't want to put it in junit-src to avoid having to recompile all the downstream
+ * dependencies after changing this class.
+ *
+ * All members must be called from the runner's main thread.
+ */
+public class RavenwoodConfigState {
+ private static final String TAG = "RavenwoodConfigState";
+
+ private final RavenwoodConfig mConfig;
+
+ public RavenwoodConfigState(RavenwoodConfig config) {
+ mConfig = config;
+ }
+
+ /** Map from path -> resources. */
+ private final HashMap<File, Resources> mCachedResources = new HashMap<>();
+
+ /**
+ * Load {@link Resources} from an APK, with cache.
+ */
+ public Resources loadResources(@Nullable File apkPath) {
+ var cached = mCachedResources.get(apkPath);
+ if (cached != null) {
+ return cached;
+ }
+
+ var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
+
+ assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
+
+ final String path = fileToLoad.getAbsolutePath();
+ final var emptyPaths = new String[0];
+
+ ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
+
+ final var ret = ResourcesManager.getInstance().getResources(null, path,
+ emptyPaths, emptyPaths, emptyPaths,
+ emptyPaths, null, null,
+ new DisplayAdjustments().getCompatibilityInfo(),
+ RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
+
+ assertNotNull(ret);
+
+ mCachedResources.put(apkPath, ret);
+ return ret;
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
index 48bed79..239c806 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
@@ -60,6 +60,8 @@
private final File mCacheDir;
private final Supplier<Resources> mResourcesSupplier;
+ private RavenwoodContext mAppContext;
+
@GuardedBy("mLock")
private Resources mResources;
@@ -77,8 +79,8 @@
mPackageName = packageName;
mMainThread = mainThread;
mResourcesSupplier = resourcesSupplier;
- mFilesDir = createTempDir("files-dir");
- mCacheDir = createTempDir("cache-dir");
+ mFilesDir = createTempDir(packageName + "_files-dir");
+ mCacheDir = createTempDir(packageName + "_cache-dir");
// Services provided by a typical shipping device
registerService(ClipboardManager.class,
@@ -131,34 +133,35 @@
@Override
public Looper getMainLooper() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getLooper();
}
@Override
public Handler getMainThreadHandler() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getThreadHandler();
}
@Override
public Executor getMainExecutor() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getThreadExecutor();
}
@Override
public String getPackageName() {
return Objects.requireNonNull(mPackageName,
- "Test must request setPackageName() via RavenwoodRule");
+ "Test must request setPackageName() (or setTargetPackageName())"
+ + " via RavenwoodConfig");
}
@Override
public String getOpPackageName() {
return Objects.requireNonNull(mPackageName,
- "Test must request setPackageName() via RavenwoodRule");
+ "Test must request setPackageName() via RavenwoodConfig");
}
@Override
@@ -227,6 +230,15 @@
return new File(RAVENWOOD_RESOURCE_APK).getAbsolutePath();
}
+ public void setApplicationContext(RavenwoodContext appContext) {
+ mAppContext = appContext;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return mAppContext;
+ }
+
/**
* Wrap the given {@link Supplier} to become memoized.
*
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index d73afd4..04b67c4 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.fail;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.GuardedBy;
@@ -35,12 +34,11 @@
import java.util.WeakHashMap;
/**
- * Used to store various states associated with the current test runner.
+ * Used to store various states associated with the current test runner that's inly needed
+ * in junit-impl.
*
- * This class could be added to {@link RavenwoodAwareTestRunner} as a field, but we don't
- * want to put it in junit-src/ (for one, that'll cause all the downstream dependencies to be
- * rebuilt when this file is updated), so we manage it separately using a Map from each
- * {@link RavenwoodAwareTestRunner} instance to a {@link RavenwoodRunnerState}.
+ * We don't want to put it in junit-src to avoid having to recompile all the downstream
+ * dependencies after changing this class.
*
* All members must be called from the runner's main thread.
*/
@@ -51,23 +49,12 @@
private static final WeakHashMap<RavenwoodAwareTestRunner, RavenwoodRunnerState> sStates =
new WeakHashMap<>();
- /**
- * Get the instance for a given runner.
- */
- public static RavenwoodRunnerState forRunner(@NonNull RavenwoodAwareTestRunner runner) {
- synchronized (sStates) {
- var ret = sStates.get(runner);
- if (ret == null) {
- ret = new RavenwoodRunnerState(runner);
- sStates.put(runner, ret);
- }
- return ret;
- }
- }
-
private final RavenwoodAwareTestRunner mRunner;
- private RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
+ /**
+ * Ctor.
+ */
+ public RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
mRunner = runner;
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 03c9001..f4756c5 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -16,12 +16,10 @@
package android.platform.test.ravenwood;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.ActivityManager;
import android.app.Instrumentation;
@@ -34,7 +32,6 @@
import android.os.Looper;
import android.os.ServiceManager;
import android.util.Log;
-import android.view.DisplayAdjustments;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -163,31 +160,52 @@
main = null;
}
- // TODO This should be integrated into LoadedApk
- final Supplier<Resources> resourcesSupplier = () -> {
- var resApkFile = new File(RAVENWOOD_RESOURCE_APK);
- if (!resApkFile.isFile()) {
- resApkFile = new File(RAVENWOOD_EMPTY_RESOURCES_APK);
- }
- assertTrue(resApkFile.isFile());
- final String res = resApkFile.getAbsolutePath();
- final var emptyPaths = new String[0];
+ final boolean isSelfInstrumenting =
+ Objects.equals(config.mTestPackageName, config.mTargetPackageName);
- ResourcesManager.getInstance().initializeApplicationPaths(res, emptyPaths);
-
- final var ret = ResourcesManager.getInstance().getResources(null, res,
- emptyPaths, emptyPaths, emptyPaths,
- emptyPaths, null, null,
- new DisplayAdjustments().getCompatibilityInfo(),
- RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
-
- assertNotNull(ret);
- return ret;
+ // This will load the resources from the apk set to `resource_apk` in the build file.
+ // This is supposed to be the "target app"'s resources.
+ final Supplier<Resources> targetResourcesLoader = () -> {
+ var file = new File(RAVENWOOD_RESOURCE_APK);
+ return config.mState.loadResources(file.exists() ? file : null);
};
+ // Set up test context's resources.
+ // If the target package name == test package name, then we use the main resources.
+ // Otherwise, we don't simulate loading resources from the test APK yet.
+ // (we need to add `test_resource_apk` to `android_ravenwood_test`)
+ final Supplier<Resources> testResourcesLoader;
+ if (isSelfInstrumenting) {
+ testResourcesLoader = targetResourcesLoader;
+ } else {
+ testResourcesLoader = () -> {
+ fail("Cannot load resources from the test context (yet)."
+ + " Use target context's resources instead.");
+ return null; // unreachable.
+ };
+ }
- config.mContext = new RavenwoodContext(config.mPackageName, main, resourcesSupplier);
+ var testContext = new RavenwoodContext(
+ config.mTestPackageName, main, testResourcesLoader);
+ var targetContext = new RavenwoodContext(
+ config.mTargetPackageName, main, targetResourcesLoader);
+
+ // Set up app context.
+ var appContext = new RavenwoodContext(
+ config.mTargetPackageName, main, targetResourcesLoader);
+ appContext.setApplicationContext(appContext);
+ if (isSelfInstrumenting) {
+ testContext.setApplicationContext(appContext);
+ targetContext.setApplicationContext(appContext);
+ } else {
+ // When instrumenting into another APK, the test context doesn't have an app context.
+ targetContext.setApplicationContext(appContext);
+ }
+ config.mTestContext = testContext;
+ config.mTargetContext = targetContext;
+
+ // Prepare other fields.
config.mInstrumentation = new Instrumentation();
- config.mInstrumentation.basicInit(config.mContext);
+ config.mInstrumentation.basicInit(config.mTestContext, config.mTargetContext);
InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
RavenwoodSystemServer.init(config);
@@ -224,10 +242,14 @@
InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
config.mInstrumentation = null;
- if (config.mContext != null) {
- ((RavenwoodContext) config.mContext).cleanUp();
+ if (config.mTestContext != null) {
+ ((RavenwoodContext) config.mTestContext).cleanUp();
}
- config.mContext = null;
+ if (config.mTargetContext != null) {
+ ((RavenwoodContext) config.mTargetContext).cleanUp();
+ }
+ config.mTestContext = null;
+ config.mTargetContext = null;
if (config.mProvideMainThread) {
Looper.getMainLooper().quit();
@@ -240,7 +262,9 @@
ServiceManager.reset$ravenwood();
setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
- Binder.restoreCallingIdentity(sOriginalIdentityToken);
+ if (sOriginalIdentityToken != -1) {
+ Binder.restoreCallingIdentity(sOriginalIdentityToken);
+ }
android.os.Process.reset$ravenwood();
ResourcesManager.setInstance(null); // Better structure needed.
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index f3a93c1..d4090e2 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -67,7 +67,7 @@
sStartedServices = new ArraySet<>();
sTimings = new TimingsTraceAndSlog();
- sServiceManager = new SystemServiceManager(config.mContext);
+ sServiceManager = new SystemServiceManager(config.mTestContext);
sServiceManager.setStartInfo(false,
SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index bc944d7..cb8af0c 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -171,6 +171,12 @@
private Description mDescription = null;
private Throwable mExceptionInConstructor = null;
+ /**
+ * Stores internal states / methods associated with this runner that's only needed in
+ * junit-impl.
+ */
+ final RavenwoodRunnerState mState = new RavenwoodRunnerState(this);
+
private Error logAndFail(String message, Throwable exception) {
Log.e(TAG, message, exception);
throw new AssertionError(message, exception);
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 04e0bed..ea33aa6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -63,7 +63,10 @@
int mUid = NOBODY_UID;
int mPid = sNextPid.getAndIncrement();
- String mPackageName;
+ String mTestPackageName;
+ String mTargetPackageName;
+
+ int mMinSdkLevel;
boolean mProvideMainThread = false;
@@ -71,9 +74,15 @@
final List<Class<?>> mServicesRequired = new ArrayList<>();
- volatile Context mContext;
+ volatile Context mTestContext;
+ volatile Context mTargetContext;
volatile Instrumentation mInstrumentation;
+ /**
+ * Stores internal states / methods associated with this config that's only needed in
+ * junit-impl.
+ */
+ final RavenwoodConfigState mState = new RavenwoodConfigState(this);
private RavenwoodConfig() {
}
@@ -84,6 +93,12 @@
return RavenwoodRule.isOnRavenwood();
}
+ private void setDefaults() {
+ if (mTargetPackageName == null) {
+ mTargetPackageName = mTestPackageName;
+ }
+ }
+
public static class Builder {
private final RavenwoodConfig mConfig = new RavenwoodConfig();
@@ -109,11 +124,28 @@
}
/**
- * Configure the identity of this process to be the given package name for the duration
- * of the test. Has no effect on non-Ravenwood environments.
+ * Configure the package name of the test, which corresponds to
+ * {@link Instrumentation#getContext()}.
*/
public Builder setPackageName(@NonNull String packageName) {
- mConfig.mPackageName = Objects.requireNonNull(packageName);
+ mConfig.mTestPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /**
+ * Configure the package name of the target app, which corresponds to
+ * {@link Instrumentation#getTargetContext()}. Defaults to {@link #setPackageName}.
+ */
+ public Builder setTargetPackageName(@NonNull String packageName) {
+ mConfig.mTargetPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /**
+ * Configure the min SDK level of the test.
+ */
+ public Builder setMinSdkLevel(int sdkLevel) {
+ mConfig.mMinSdkLevel = sdkLevel;
return this;
}
@@ -178,6 +210,7 @@
}
public RavenwoodConfig build() {
+ mConfig.setDefaults();
return mConfig;
}
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 7847e7c..984106b 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -216,7 +216,7 @@
*/
@Deprecated
public Context getContext() {
- return Objects.requireNonNull(mConfiguration.mContext,
+ return Objects.requireNonNull(mConfiguration.mTestContext,
"Context is only available during @Test execution");
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
similarity index 69%
rename from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
rename to ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
index 48ec198..43a28ba 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
@@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.platform.test.ravenwood;
-package com.android.systemui.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
+/** Stub class. The actual implementaetion is in junit-impl-src. */
+public class RavenwoodConfigState {
+ public RavenwoodConfigState(RavenwoodConfig config) {
+ }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
similarity index 69%
copy from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
copy to ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index 48ec198..83cbc52 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.platform.test.ravenwood;
-package com.android.systemui.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
+/** Stub class. The actual implementaetion is in junit-impl-src. */
+public class RavenwoodRunnerState {
+ public RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
+ }
}
diff --git a/ravenwood/tests/bivalentinst/Android.bp b/ravenwood/tests/bivalentinst/Android.bp
new file mode 100644
index 0000000..38d1b299
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/Android.bp
@@ -0,0 +1,149 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_ravenwood_test {
+ name: "RavenwoodBivalentInstTest_self_inst",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_nonself.java",
+ ],
+
+ static_libs: [
+ "RavenwoodBivalentInstTest_self_inst_device_R",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit",
+ "truth",
+ ],
+ // TODO(b/366246777) uncomment it and the test.
+ // resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
+ auto_gen_config: true,
+}
+
+android_ravenwood_test {
+ name: "RavenwoodBivalentInstTest_nonself_inst",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_self.java",
+ ],
+
+ static_libs: [
+ "RavenwoodBivalentInstTestTarget_R",
+ "RavenwoodBivalentInstTest_nonself_inst_device_R",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit",
+ "truth",
+ ],
+ // TODO(b/366246777) uncomment it and the test.
+ // resource_apk: "RavenwoodBivalentInstTestTarget",
+ auto_gen_config: true,
+}
+
+// We have 3 R.javas from the 3 packages (2 test apks below, and 1 target APK)
+// RavenwoodBivalentInstTest needs to use all of them, but we can't add all the
+// {.aapt.srcjar}'s together because that'd cause
+// "duplicate declaration of androidx.test.core.R$string."
+// So we build them as separate libraries, and include them as static_libs.
+java_library {
+ name: "RavenwoodBivalentInstTestTarget_R",
+ srcs: [
+ ":RavenwoodBivalentInstTestTarget{.aapt.srcjar}",
+ ],
+}
+
+java_library {
+ name: "RavenwoodBivalentInstTest_self_inst_device_R",
+ srcs: [
+ ":RavenwoodBivalentInstTest_self_inst_device{.aapt.srcjar}",
+ ],
+}
+
+java_library {
+ name: "RavenwoodBivalentInstTest_nonself_inst_device_R",
+ srcs: [
+ ":RavenwoodBivalentInstTest_nonself_inst_device{.aapt.srcjar}",
+ ],
+}
+
+android_test {
+ name: "RavenwoodBivalentInstTest_self_inst_device",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_nonself.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "ravenwood-junit",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ use_resource_processor: false,
+ manifest: "AndroidManifest-self-inst.xml",
+ test_config: "AndroidTest-self-inst.xml",
+ optimize: {
+ enabled: false,
+ },
+}
+
+android_test {
+ name: "RavenwoodBivalentInstTest_nonself_inst_device",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_self.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "ravenwood-junit",
+ ],
+ data: [
+ ":RavenwoodBivalentInstTestTarget",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ use_resource_processor: false,
+ manifest: "AndroidManifest-nonself-inst.xml",
+ test_config: "AndroidTest-nonself-inst.xml",
+ instrumentation_for: "RavenwoodBivalentInstTestTarget",
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml b/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml
new file mode 100644
index 0000000..a5a1f17
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ravenwood.bivalentinsttest_nonself_inst">
+
+ <application android:debuggable="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.ravenwood.bivalentinst_target_app"
+ />
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml b/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml
new file mode 100644
index 0000000..3dc4c56
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ravenwood.bivalentinsttest_self_inst">
+
+ <application android:debuggable="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.ravenwood.bivalentinsttest_self_inst"
+ />
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml b/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml
new file mode 100644
index 0000000..9491c53
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTestTarget.apk" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTest_nonself_inst_device.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.ravenwood.bivalentinsttest_nonself_inst" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml b/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml
new file mode 100644
index 0000000..3079c06
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTest_self_inst_device.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.ravenwood.bivalentinsttest_self_inst" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/ravenwood/tests/bivalentinst/res/values/strings.xml b/ravenwood/tests/bivalentinst/res/values/strings.xml
new file mode 100644
index 0000000..73ef650
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="test_string_in_test">String in test APK</string>
+</resources>
diff --git a/ravenwood/tests/bivalentinst/targetapp/Android.bp b/ravenwood/tests/bivalentinst/targetapp/Android.bp
new file mode 100644
index 0000000..7528a62
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/Android.bp
@@ -0,0 +1,20 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+ name: "RavenwoodBivalentInstTestTarget",
+ srcs: [
+ "src/**/*.java",
+ ],
+ sdk_version: "current",
+ optimize: {
+ enabled: false,
+ },
+ use_resource_processor: false,
+}
diff --git a/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml b/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml
new file mode 100644
index 0000000..0715f5d
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ravenwood.bivalentinst_target_app">
+ <application>
+ </application>
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml b/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml
new file mode 100644
index 0000000..395bc2a
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="test_string_in_target">Test string in target APK</string>
+</resources>
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
similarity index 69%
copy from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
copy to ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
index 48ec198..15e50ec 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
@@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.ravenwoodtest.bivalentinst;
-package com.android.systemui.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
+/**
+ * Empty class. We need it because an instrumentation target APK must have code.
+ */
+public class Empty {
}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
new file mode 100644
index 0000000..9f3ca6f
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalentinst;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodConfig.Config;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the case where the instrumentation target is _not_ the test APK itself.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodInstrumentationTest_nonself {
+ private static final String TARGET_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinst_target_app";
+ private static final String TEST_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_nonself_inst";
+
+ @Config
+ public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setTargetPackageName(TARGET_PACKAGE_NAME)
+ .build();
+
+ private static Instrumentation sInstrumentation;
+ private static Context sTestContext;
+ private static Context sTargetContext;
+
+ @BeforeClass
+ public static void beforeClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sTestContext = sInstrumentation.getContext();
+ sTargetContext = sInstrumentation.getTargetContext();
+ }
+
+ @Test
+ public void testTestContextPackageName() {
+ assertThat(sTestContext.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetContextPackageName() {
+ assertThat(sTargetContext.getPackageName()).isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppContext() {
+ // Test context doesn't have an app context.
+ assertThat(sTestContext.getApplicationContext()).isNull();
+ }
+
+ @Test
+ public void testTargetAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testContextSameness() {
+ assertThat(sTargetContext).isNotSameInstanceAs(sTestContext);
+
+ assertThat(sTargetContext).isNotSameInstanceAs(sTargetContext.getApplicationContext());
+
+ assertThat(sTargetContext.getApplicationContext()).isSameInstanceAs(
+ sTargetContext.getApplicationContext().getApplicationContext());
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTargetAppResource() {
+ assertThat(sTargetContext.getString(
+ com.android.ravenwood.bivalentinst_target_app.R.string.test_string_in_target))
+ .isEqualTo("Test string in target APK");
+ }
+
+ @Test
+ @DisabledOnRavenwood(
+ reason = "Loading resources from non-self-instrumenting test APK isn't supported yet")
+ public void testTestAppResource() {
+ assertThat(sTestContext.getString(
+ com.android.ravenwood.bivalentinsttest_nonself_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
new file mode 100644
index 0000000..fdff222
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalentinst;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodConfig.Config;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the case where the instrumentation target is the test APK itself.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodInstrumentationTest_self {
+
+ private static final String TARGET_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_self_inst";
+ private static final String TEST_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_self_inst";
+
+ @Config
+ public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setTargetPackageName(TARGET_PACKAGE_NAME)
+ .build();
+
+
+ private static Instrumentation sInstrumentation;
+ private static Context sTestContext;
+ private static Context sTargetContext;
+
+ @BeforeClass
+ public static void beforeClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sTestContext = sInstrumentation.getContext();
+ sTargetContext = sInstrumentation.getTargetContext();
+ }
+
+ @Test
+ public void testTestContextPackageName() {
+ assertThat(sTestContext.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetContextPackageName() {
+ assertThat(sTargetContext.getPackageName()).isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppContextPackageName() {
+ assertThat(sTestContext.getApplicationContext().getPackageName())
+ .isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppAppContextPackageName() {
+ assertThat(sTestContext.getApplicationContext().getPackageName())
+ .isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testContextSameness() {
+ assertThat(sTargetContext).isNotSameInstanceAs(sTestContext);
+
+ assertThat(sTestContext).isNotSameInstanceAs(sTestContext.getApplicationContext());
+ assertThat(sTargetContext).isNotSameInstanceAs(sTargetContext.getApplicationContext());
+
+ assertThat(sTestContext.getApplicationContext()).isSameInstanceAs(
+ sTestContext.getApplicationContext().getApplicationContext());
+ assertThat(sTargetContext.getApplicationContext()).isSameInstanceAs(
+ sTargetContext.getApplicationContext().getApplicationContext());
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTargetAppResource() {
+ assertThat(sTargetContext.getString(
+ com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTestAppResource() {
+ assertThat(sTestContext.getString(
+ com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+}
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
index a38512e..f7f9a85 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
@@ -127,7 +127,7 @@
}
}
- stats.totalProcessTime = log.iTime("$executableName processing $inJar") {
+ stats.totalProcessTime = log.vTime("$executableName processing $inJar") {
ZipFile(inJar).use { inZip ->
val inEntries = inZip.entries()
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
index e8341e5..10fe0a3 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
@@ -20,6 +20,20 @@
import com.android.hoststubgen.SetOnce
import com.android.hoststubgen.ensureFileExists
import com.android.hoststubgen.log
+import java.nio.file.Paths
+import kotlin.io.path.exists
+
+/**
+ * If this file exits, we also read options from it. This is "unsafe" because it could break
+ * incremental builds, if it sets any flag that affects the output file.
+ * (however, for now, there's no such options.)
+ *
+ * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
+ *
+ * (but even the content of this file changes, soong won't rerun the command, so you need to
+ * remove the output first and then do a build again.)
+ */
+private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.raveniezr-unsafe"
class RavenizerOptions(
/** Input jar file*/
@@ -35,9 +49,16 @@
var fatalValidation: SetOnce<Boolean> = SetOnce(false),
) {
companion object {
- fun parseArgs(args: Array<String>): RavenizerOptions {
+
+ fun parseArgs(origArgs: Array<String>): RavenizerOptions {
+ val args = origArgs.toMutableList()
+ if (Paths.get(RAVENIZER_DOTFILE).exists()) {
+ log.i("Reading options from $RAVENIZER_DOTFILE")
+ args.add(0, "@$RAVENIZER_DOTFILE")
+ }
+
val ret = RavenizerOptions()
- val ai = ArgIterator.withAtFiles(args)
+ val ai = ArgIterator.withAtFiles(args.toTypedArray())
while (true) {
val arg = ai.nextArgOptional()
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
index bd9d96d..cf6d6f6 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
@@ -184,7 +184,7 @@
av.visit("value", ravenwoodTestRunnerType.type)
av.visitEnd()
}
- log.i("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
+ log.v("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
}
/*
@@ -442,7 +442,7 @@
// Don't process a class if it has a @NoRavenizer annotation.
classes.findClass(className)?.let { cn ->
if (cn.findAnyAnnotation(noRavenizerAnotType.descAsSet) != null) {
- log.w("Class ${className.toHumanReadableClassName()} has" +
+ log.i("Class ${className.toHumanReadableClassName()} has" +
" @${noRavenizerAnotType.humanReadableName}. Skipping."
)
return false
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index b97ff62..9fd2f31 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -20,11 +20,6 @@
defaults: [
"platform_service_defaults",
],
- lint: {
- error_checks: ["MissingPermissionAnnotation"],
- baseline_filename: "lint-baseline.xml",
-
- },
srcs: [
":services.accessibility-sources",
"//frameworks/base/packages/SettingsLib/RestrictedLockUtils:SettingsLibRestrictedLockUtilsSrc",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 1b2447e..617cca9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -67,7 +67,6 @@
*
* NOTE: This class has to be created and poked only from the main thread.
*/
-@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
index e10e87c..c9ec16e 100644
--- a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -33,7 +33,6 @@
/**
* Encapsulate fingerprint gesture logic
*/
-@SuppressWarnings("MissingPermissionAnnotation")
public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
implements Handler.Callback{
private static final int MSG_REGISTER = 1;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
new file mode 100644
index 0000000..c3b7087
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.appfunctions;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/** Executors for App function operations. */
+public final class AppFunctionExecutors {
+
+ /** Executor for operations that do not need to block. */
+ public static final Executor THREAD_POOL_EXECUTOR =
+ new ThreadPoolExecutor(
+ /* corePoolSize= */ Runtime.getRuntime().availableProcessors(),
+ /* maxConcurrency= */ Runtime.getRuntime().availableProcessors(),
+ /* keepAliveTime= */ 0L,
+ /* unit= */ TimeUnit.SECONDS,
+ /* workQueue= */ new LinkedBlockingQueue<>());
+
+ private AppFunctionExecutors() {}
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index f04bd9f..269419f 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -16,6 +16,8 @@
package com.android.server.appfunctions;
+import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR;
+
import android.annotation.NonNull;
import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
import android.app.appfunctions.ExecuteAppFunctionResponse;
@@ -29,6 +31,7 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
+import android.app.appsearch.AppSearchResult;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
@@ -51,14 +54,7 @@
public AppFunctionManagerServiceImpl(@NonNull Context context) {
this(
new RemoteServiceCallerImpl<>(
- context,
- IAppFunctionService.Stub::asInterface,
- new ThreadPoolExecutor(
- /* corePoolSize= */ Runtime.getRuntime().availableProcessors(),
- /* maxConcurrency= */ Runtime.getRuntime().availableProcessors(),
- /* keepAliveTime= */ 0L,
- /* unit= */ TimeUnit.SECONDS,
- /* workQueue= */ new LinkedBlockingQueue<>())),
+ context, IAppFunctionService.Stub::asInterface, THREAD_POOL_EXECUTOR),
new CallerValidatorImpl(context),
new ServiceHelperImpl(context),
new ServiceConfigImpl());
@@ -86,6 +82,17 @@
final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback);
+ try {
+ executeAppFunctionInternal(requestInternal, safeExecuteAppFunctionCallback);
+ } catch (Exception e) {
+ safeExecuteAppFunctionCallback.onResult(mapExceptionToExecuteAppFunctionResponse(e));
+ }
+ }
+
+ private void executeAppFunctionInternal(
+ ExecuteAppFunctionAidlRequest requestInternal,
+ SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
+
String validatedCallingPackage;
UserHandle targetUser;
try {
@@ -124,39 +131,53 @@
return;
}
- if (!mCallerValidator.verifyCallerCanExecuteAppFunction(
- validatedCallingPackage, targetPackageName)) {
- safeExecuteAppFunctionCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_DENIED,
- "Caller does not have permission to execute the appfunction",
- /* extras= */ null));
- return;
- }
-
- Intent serviceIntent =
- mInternalServiceHelper.resolveAppFunctionService(targetPackageName, targetUser);
- if (serviceIntent == null) {
- safeExecuteAppFunctionCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
- "Cannot find the target service.",
- /* extras= */ null));
- return;
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- bindAppFunctionServiceUnchecked(
- requestInternal,
- serviceIntent,
- targetUser,
- safeExecuteAppFunctionCallback,
- /* bindFlags= */ Context.BIND_AUTO_CREATE,
- /* timeoutInMillis= */ mServiceConfig.getExecuteAppFunctionTimeoutMillis());
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ var unused = mCallerValidator
+ .verifyCallerCanExecuteAppFunction(
+ validatedCallingPackage,
+ targetPackageName,
+ requestInternal.getClientRequest().getFunctionIdentifier())
+ .thenAccept(
+ canExecute -> {
+ if (!canExecute) {
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_DENIED,
+ "Caller does not have permission to execute the"
+ + " appfunction",
+ /* extras= */ null));
+ return;
+ }
+ Intent serviceIntent =
+ mInternalServiceHelper.resolveAppFunctionService(
+ targetPackageName, targetUser);
+ if (serviceIntent == null) {
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ "Cannot find the target service.",
+ /* extras= */ null));
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ bindAppFunctionServiceUnchecked(
+ requestInternal,
+ serviceIntent,
+ targetUser,
+ safeExecuteAppFunctionCallback,
+ /* bindFlags= */ Context.BIND_AUTO_CREATE,
+ /* timeoutInMillis= */ mServiceConfig
+ .getExecuteAppFunctionTimeoutMillis());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ })
+ .exceptionally(
+ ex -> {
+ safeExecuteAppFunctionCallback.onResult(
+ mapExceptionToExecuteAppFunctionResponse(ex));
+ return null;
+ });
}
private void bindAppFunctionServiceUnchecked(
@@ -232,4 +253,37 @@
/* extras= */ null));
}
}
+
+ private ExecuteAppFunctionResponse mapExceptionToExecuteAppFunctionResponse(Throwable e) {
+ if (e instanceof AppSearchException) {
+ AppSearchException appSearchException = (AppSearchException) e;
+ return ExecuteAppFunctionResponse.newFailure(
+ mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(
+ appSearchException.getResultCode()),
+ appSearchException.getMessage(),
+ /* extras= */ null);
+ }
+
+ return ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ e.getMessage(),
+ /* extras= */ null);
+ }
+
+ private int mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(int resultCode) {
+ if (resultCode == AppSearchResult.RESULT_OK) {
+ throw new IllegalArgumentException(
+ "This method can only be used to convert failure result codes.");
+ }
+
+ switch (resultCode) {
+ case AppSearchResult.RESULT_NOT_FOUND:
+ return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
+ case AppSearchResult.RESULT_INVALID_ARGUMENT:
+ case AppSearchResult.RESULT_INTERNAL_ERROR:
+ case AppSearchResult.RESULT_SECURITY_ERROR:
+ // fall-through
+ }
+ return ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR;
+ }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java b/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java
new file mode 100644
index 0000000..c23470a
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.appfunctions;
+
+import android.app.appsearch.AppSearchResult;
+
+/** Exception to wrap failure result codes returned by AppSearch. */
+public class AppSearchException extends RuntimeException {
+ private final int resultCode;
+
+ public AppSearchException(int resultCode, String message) {
+ super(message);
+ this.resultCode = resultCode;
+ }
+
+ /**
+ * Returns the result code used to create this exception, typically one of the {@link
+ * AppSearchResult} result codes.
+ */
+ public int getResultCode() {
+ return resultCode;
+ }
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
index ca43dfa..e7a861e 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
@@ -21,6 +21,7 @@
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
/**
* Interface for validating that the caller has the correct privilege to call an AppFunctionManager
@@ -65,10 +66,13 @@
*
* @param callerPackageName The calling package (as previously validated).
* @param targetPackageName The package that owns the app function to execute.
+ * @param functionId The id of the app function to execute.
* @return Whether the caller can execute the specified app function.
*/
- boolean verifyCallerCanExecuteAppFunction(
- @NonNull String callerPackageName, @NonNull String targetPackageName);
+ AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction(
+ @NonNull String callerPackageName,
+ @NonNull String targetPackageName,
+ @NonNull String functionId);
/**
* Checks if the user is organization managed.
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
index 618a5ae..94a63b4 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
@@ -16,11 +16,23 @@
package com.android.server.appfunctions;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction;
+import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR;
+
import android.Manifest;
import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.app.admin.DevicePolicyManager;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchManager.SearchContext;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.GenericDocument;
+import android.app.appsearch.GetByDocumentIdRequest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -28,6 +40,7 @@
import android.os.UserHandle;
import android.os.UserManager;
+import com.android.internal.infra.AndroidFuture;
import java.util.Objects;
/* Validates that caller has the correct privilege to call an AppFunctionManager Api. */
@@ -76,11 +89,12 @@
Manifest.permission.EXECUTE_APP_FUNCTIONS
},
conditional = true)
- // TODO(b/360864791): Add and honor apps that opt-out from EXECUTE_APP_FUNCTIONS caller.
- public boolean verifyCallerCanExecuteAppFunction(
- @NonNull String callerPackageName, @NonNull String targetPackageName) {
+ public AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction(
+ @NonNull String callerPackageName,
+ @NonNull String targetPackageName,
+ @NonNull String functionId) {
if (callerPackageName.equals(targetPackageName)) {
- return true;
+ return AndroidFuture.completedFuture(true);
}
int pid = Binder.getCallingPid();
@@ -89,10 +103,67 @@
mContext.checkPermission(
Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, pid, uid)
== PackageManager.PERMISSION_GRANTED;
+
+ if (hasTrustedExecutionPermission) {
+ return AndroidFuture.completedFuture(true);
+ }
+
boolean hasExecutionPermission =
mContext.checkPermission(Manifest.permission.EXECUTE_APP_FUNCTIONS, pid, uid)
== PackageManager.PERMISSION_GRANTED;
- return hasExecutionPermission || hasTrustedExecutionPermission;
+
+ if (!hasExecutionPermission) {
+ return AndroidFuture.completedFuture(false);
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ FutureAppSearchSession futureAppSearchSession =
+ new FutureAppSearchSessionImpl(
+ mContext.getSystemService(AppSearchManager.class),
+ THREAD_POOL_EXECUTOR,
+ new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build());
+
+ String documentId = getDocumentIdForAppFunction(targetPackageName, functionId);
+
+ return futureAppSearchSession
+ .getByDocumentId(
+ new GetByDocumentIdRequest.Builder(APP_FUNCTION_STATIC_NAMESPACE)
+ .addIds(documentId)
+ .build())
+ .thenApply(
+ batchResult ->
+ getGenericDocumentFromBatchResult(batchResult, documentId))
+ .thenApply(
+ CallerValidatorImpl::getRestrictCallersWithExecuteAppFunctionsProperty)
+ .thenApply(
+ restrictCallersWithExecuteAppFunctions ->
+ !restrictCallersWithExecuteAppFunctions
+ && hasExecutionPermission);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private static GenericDocument getGenericDocumentFromBatchResult(
+ AppSearchBatchResult<String, GenericDocument> result, String documentId) {
+ if (result.isSuccess()) {
+ return result.getSuccesses().get(documentId);
+ }
+
+ AppSearchResult<GenericDocument> failedResult = result.getFailures().get(documentId);
+ throw new AppSearchException(
+ failedResult.getResultCode(),
+ "Unable to retrieve document with id: "
+ + documentId
+ + " due to "
+ + failedResult.getErrorMessage());
+ }
+
+ private static boolean getRestrictCallersWithExecuteAppFunctionsProperty(
+ GenericDocument genericDocument) {
+ return genericDocument.getPropertyBoolean(
+ STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS);
}
@Override
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index b1c25c4..0044b4b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -26,7 +26,6 @@
import android.app.appsearch.PutDocumentsRequest;
import android.app.appsearch.RemoveByDocumentIdRequest;
import android.app.appsearch.SearchResult;
-import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaRequest;
import android.app.appsearch.SetSchemaResponse;
@@ -36,8 +35,6 @@
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
/** A future API wrapper of {@link AppSearchSession} APIs. */
public interface FutureAppSearchSession extends Closeable {
@@ -78,7 +75,7 @@
* AppSearchSession} database.
*/
AndroidFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentId(
- GetByDocumentIdRequest getRequest);
+ @NonNull GetByDocumentIdRequest getRequest);
/**
* Retrieves documents from the open {@link AppSearchSession} that match a given query string
@@ -88,29 +85,15 @@
@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
/** A future API wrapper of {@link android.app.appsearch.SearchResults}. */
- class FutureSearchResults {
- private final SearchResults mSearchResults;
- private final Executor mExecutor;
+ interface FutureSearchResults {
- public FutureSearchResults(
- @NonNull SearchResults searchResults, @NonNull Executor executor) {
- mSearchResults = Objects.requireNonNull(searchResults);
- mExecutor = Objects.requireNonNull(executor);
- }
-
- public AndroidFuture<List<SearchResult>> getNextPage() {
- AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture =
- new AndroidFuture<>();
-
- mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
- return nextPageFuture.thenApply(
- result -> {
- if (result.isSuccess()) {
- return result.getResultValue();
- } else {
- throw new RuntimeException(failedResultToException(result));
- }
- });
- }
+ /**
+ * Retrieves the next page of {@link SearchResult} objects from the {@link AppSearchSession}
+ * database.
+ *
+ * <p>Continue calling this method to access results until it returns an empty list,
+ * signifying there are no more results.
+ */
+ AndroidFuture<List<SearchResult>> getNextPage();
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
index e78f390..3079d9f 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
@@ -30,6 +30,8 @@
import android.app.appsearch.GetSchemaResponse;
import android.app.appsearch.PutDocumentsRequest;
import android.app.appsearch.RemoveByDocumentIdRequest;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaRequest;
import android.app.appsearch.SetSchemaResponse;
@@ -37,6 +39,7 @@
import com.android.internal.infra.AndroidFuture;
import java.io.IOException;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -176,12 +179,39 @@
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
return getSessionAsync()
.thenApply(session -> session.search(queryExpression, searchSpec))
- .thenApply(result -> new FutureSearchResults(result, mExecutor));
+ .thenApply(result -> new FutureSearchResultsImpl(result, mExecutor));
}
@Override
public void close() throws IOException {}
+ private static final class FutureSearchResultsImpl implements FutureSearchResults {
+ private final SearchResults mSearchResults;
+ private final Executor mExecutor;
+
+ private FutureSearchResultsImpl(
+ @NonNull SearchResults searchResults, @NonNull Executor executor) {
+ this.mSearchResults = searchResults;
+ this.mExecutor = executor;
+ }
+
+ @Override
+ public AndroidFuture<List<SearchResult>> getNextPage() {
+ AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture =
+ new AndroidFuture<>();
+
+ mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
+ return nextPageFuture.thenApply(
+ result -> {
+ if (result.isSuccess()) {
+ return result.getResultValue();
+ } else {
+ throw new RuntimeException(failedResultToException(result));
+ }
+ });
+ }
+ }
+
private static final class BatchResultCallbackAdapter<K, V>
implements BatchResultCallback<K, V> {
private final AndroidFuture<AppSearchBatchResult<K, V>> mFuture;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
index 01e1008..d140258 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
@@ -16,35 +16,244 @@
package com.android.server.appfunctions;
+import static android.app.appfunctions.AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.WorkerThread;
+import android.app.appfunctions.AppFunctionRuntimeMetadata;
+import android.app.appfunctions.AppFunctionStaticMetadataHelper;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.PropertyPath;
+import android.app.appsearch.PutDocumentsRequest;
+import android.app.appsearch.RemoveByDocumentIdRequest;
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchSpec;
+import android.app.appsearch.SetSchemaRequest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
* This class implements helper methods for synchronously interacting with AppSearch while
* synchronizing AppFunction runtime and static metadata.
+ *
+ * <p>This class is not thread safe.
*/
public class MetadataSyncAdapter {
- private final FutureAppSearchSession mFutureAppSearchSession;
+ private static final String TAG = MetadataSyncAdapter.class.getSimpleName();
+ private final FutureAppSearchSession mRuntimeMetadataSearchSession;
+ private final FutureAppSearchSession mStaticMetadataSearchSession;
private final Executor mSyncExecutor;
+ private final PackageManager mPackageManager;
+
+ // Hidden constants in {@link SetSchemaRequest} that restricts runtime metadata visibility
+ // by permissions.
+ public static final int EXECUTE_APP_FUNCTIONS = 9;
+ public static final int EXECUTE_APP_FUNCTIONS_TRUSTED = 10;
public MetadataSyncAdapter(
@NonNull Executor syncExecutor,
- @NonNull FutureAppSearchSession futureAppSearchSession) {
+ @NonNull FutureAppSearchSession runtimeMetadataSearchSession,
+ @NonNull FutureAppSearchSession staticMetadataSearchSession,
+ @NonNull PackageManager packageManager) {
mSyncExecutor = Objects.requireNonNull(syncExecutor);
- mFutureAppSearchSession = Objects.requireNonNull(futureAppSearchSession);
+ mRuntimeMetadataSearchSession = Objects.requireNonNull(runtimeMetadataSearchSession);
+ mStaticMetadataSearchSession = Objects.requireNonNull(staticMetadataSearchSession);
+ mPackageManager = Objects.requireNonNull(packageManager);
+ }
+
+ /**
+ * This method submits a request to synchronize the AppFunction runtime and static metadata.
+ *
+ * @return A {@link AndroidFuture} that completes with a boolean value indicating whether the
+ * synchronization was successful.
+ */
+ public AndroidFuture<Boolean> submitSyncRequest() {
+ AndroidFuture<Boolean> settableSyncStatus = new AndroidFuture<>();
+ mSyncExecutor.execute(
+ () -> {
+ try {
+ trySyncAppFunctionMetadataBlocking();
+ settableSyncStatus.complete(true);
+ } catch (Exception e) {
+ settableSyncStatus.completeExceptionally(e);
+ }
+ });
+ return settableSyncStatus;
+ }
+
+ @WorkerThread
+ private void trySyncAppFunctionMetadataBlocking()
+ throws ExecutionException, InterruptedException {
+ ArrayMap<String, ArraySet<String>> staticPackageToFunctionMap =
+ getPackageToFunctionIdMap(
+ mStaticMetadataSearchSession,
+ AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
+ AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
+ AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME);
+ ArrayMap<String, ArraySet<String>> runtimePackageToFunctionMap =
+ getPackageToFunctionIdMap(
+ mRuntimeMetadataSearchSession,
+ RUNTIME_SCHEMA_TYPE,
+ AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
+ AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME);
+
+ ArrayMap<String, ArraySet<String>> addedFunctionsDiffMap =
+ getAddedFunctionsDiffMap(staticPackageToFunctionMap, runtimePackageToFunctionMap);
+ ArrayMap<String, ArraySet<String>> removedFunctionsDiffMap =
+ getRemovedFunctionsDiffMap(staticPackageToFunctionMap, runtimePackageToFunctionMap);
+
+ Set<AppSearchSchema> appRuntimeMetadataSchemas =
+ getAllRuntimeMetadataSchemas(staticPackageToFunctionMap.keySet());
+ appRuntimeMetadataSchemas.add(
+ AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema());
+
+ // Operation order matters here. i.e. remove -> setSchema -> add. Otherwise we would
+ // encounter an error trying to delete a document with no existing schema.
+ if (!removedFunctionsDiffMap.isEmpty()) {
+ RemoveByDocumentIdRequest removeByDocumentIdRequest =
+ buildRemoveRuntimeMetadataRequest(removedFunctionsDiffMap);
+ AppSearchBatchResult<String, Void> removeDocumentBatchResult =
+ mRuntimeMetadataSearchSession.remove(removeByDocumentIdRequest).get();
+ if (!removeDocumentBatchResult.isSuccess()) {
+ throw convertFailedAppSearchResultToException(
+ removeDocumentBatchResult.getFailures().values());
+ }
+ }
+
+ if (!addedFunctionsDiffMap.isEmpty()) {
+ // TODO(b/357551503): only set schema on package diff
+ SetSchemaRequest addSetSchemaRequest =
+ buildSetSchemaRequestForRuntimeMetadataSchemas(appRuntimeMetadataSchemas);
+ Objects.requireNonNull(
+ mRuntimeMetadataSearchSession.setSchema(addSetSchemaRequest).get());
+ PutDocumentsRequest putDocumentsRequest =
+ buildPutRuntimeMetadataRequest(addedFunctionsDiffMap);
+ AppSearchBatchResult<String, Void> putDocumentBatchResult =
+ mRuntimeMetadataSearchSession.put(putDocumentsRequest).get();
+ if (!putDocumentBatchResult.isSuccess()) {
+ throw convertFailedAppSearchResultToException(
+ putDocumentBatchResult.getFailures().values());
+ }
+ }
+ }
+
+ @NonNull
+ private static IllegalStateException convertFailedAppSearchResultToException(
+ @NonNull Collection<AppSearchResult<Void>> appSearchResult) {
+ Objects.requireNonNull(appSearchResult);
+ StringBuilder errorMessages = new StringBuilder();
+ for (AppSearchResult<Void> result : appSearchResult) {
+ errorMessages.append(result.getErrorMessage());
+ }
+ return new IllegalStateException(errorMessages.toString());
+ }
+
+ @NonNull
+ private PutDocumentsRequest buildPutRuntimeMetadataRequest(
+ @NonNull ArrayMap<String, ArraySet<String>> addedFunctionsDiffMap) {
+ Objects.requireNonNull(addedFunctionsDiffMap);
+ PutDocumentsRequest.Builder putDocumentRequestBuilder = new PutDocumentsRequest.Builder();
+
+ for (int i = 0; i < addedFunctionsDiffMap.size(); i++) {
+ String packageName = addedFunctionsDiffMap.keyAt(i);
+ ArraySet<String> addedFunctionIds = addedFunctionsDiffMap.valueAt(i);
+ for (String addedFunctionId : addedFunctionIds) {
+ putDocumentRequestBuilder.addGenericDocuments(
+ new AppFunctionRuntimeMetadata.Builder(
+ packageName,
+ addedFunctionId,
+ AppFunctionRuntimeMetadata
+ .PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ .build());
+ }
+ }
+ return putDocumentRequestBuilder.build();
+ }
+
+ @NonNull
+ private RemoveByDocumentIdRequest buildRemoveRuntimeMetadataRequest(
+ @NonNull ArrayMap<String, ArraySet<String>> removedFunctionsDiffMap) {
+ Objects.requireNonNull(AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE);
+ Objects.requireNonNull(removedFunctionsDiffMap);
+ RemoveByDocumentIdRequest.Builder removeDocumentRequestBuilder =
+ new RemoveByDocumentIdRequest.Builder(
+ AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE);
+
+ for (int i = 0; i < removedFunctionsDiffMap.size(); i++) {
+ String packageName = removedFunctionsDiffMap.keyAt(i);
+ ArraySet<String> removedFunctionIds = removedFunctionsDiffMap.valueAt(i);
+ for (String functionId : removedFunctionIds) {
+ String documentId =
+ AppFunctionRuntimeMetadata.getDocumentIdForAppFunction(
+ packageName, functionId);
+ removeDocumentRequestBuilder.addIds(documentId);
+ }
+ }
+ return removeDocumentRequestBuilder.build();
+ }
+
+ @NonNull
+ private SetSchemaRequest buildSetSchemaRequestForRuntimeMetadataSchemas(
+ @NonNull Set<AppSearchSchema> metadataSchemaSet) {
+ Objects.requireNonNull(metadataSchemaSet);
+ SetSchemaRequest.Builder setSchemaRequestBuilder =
+ new SetSchemaRequest.Builder().setForceOverride(true).addSchemas(metadataSchemaSet);
+
+ for (AppSearchSchema runtimeMetadataSchema : metadataSchemaSet) {
+ String packageName =
+ AppFunctionRuntimeMetadata.getPackageNameFromSchema(
+ runtimeMetadataSchema.getSchemaType());
+ byte[] packageCert = getCertificate(packageName);
+ if (packageCert == null) {
+ continue;
+ }
+ setSchemaRequestBuilder.setSchemaTypeVisibilityForPackage(
+ runtimeMetadataSchema.getSchemaType(),
+ true,
+ new PackageIdentifier(packageName, packageCert));
+ }
+
+ setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS));
+ setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS_TRUSTED));
+ return setSchemaRequestBuilder.build();
+ }
+
+ @NonNull
+ @WorkerThread
+ private Set<AppSearchSchema> getAllRuntimeMetadataSchemas(
+ @NonNull Set<String> staticMetadataPackages) {
+ Objects.requireNonNull(staticMetadataPackages);
+
+ Set<AppSearchSchema> appRuntimeMetadataSchemas = new ArraySet<>();
+ for (String packageName : staticMetadataPackages) {
+ appRuntimeMetadataSchemas.add(
+ AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(packageName));
+ }
+
+ return appRuntimeMetadataSchemas;
}
/**
@@ -123,13 +332,17 @@
* This method returns a map of package names to a set of function ids from the AppFunction
* metadata.
*
- * @param schemaType The name space of the AppFunction metadata.
+ * @param searchSession The {@link FutureAppSearchSession} to search the AppFunction metadata.
+ * @param schemaType The schema type of the AppFunction metadata.
+ * @param propertyFunctionId The property name of the function id in the AppFunction metadata.
+ * @param propertyPackageName The property name of the package name in the AppFunction metadata.
* @return A map of package names to a set of function ids from the AppFunction metadata.
*/
@NonNull
@VisibleForTesting
@WorkerThread
- ArrayMap<String, ArraySet<String>> getPackageToFunctionIdMap(
+ static ArrayMap<String, ArraySet<String>> getPackageToFunctionIdMap(
+ @NonNull FutureAppSearchSession searchSession,
@NonNull String schemaType,
@NonNull String propertyFunctionId,
@NonNull String propertyPackageName)
@@ -140,7 +353,7 @@
ArrayMap<String, ArraySet<String>> packageToFunctionIds = new ArrayMap<>();
FutureSearchResults futureSearchResults =
- mFutureAppSearchSession
+ searchSession
.search(
"",
buildMetadataSearchSpec(
@@ -188,4 +401,39 @@
new PropertyPath(propertyPackageName)))
.build();
}
+
+ /** Gets the SHA-256 certificate from a {@link PackageManager}, or null if it is not found. */
+ @Nullable
+ private byte[] getCertificate(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ PackageInfo packageInfo;
+ try {
+ packageInfo =
+ Objects.requireNonNull(
+ mPackageManager.getPackageInfo(
+ packageName,
+ PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES));
+ } catch (Exception e) {
+ Slog.d(TAG, "Package name info not found for package: " + packageName);
+ return null;
+ }
+ if (packageInfo.signingInfo == null) {
+ Slog.d(TAG, "Signing info not found for package: " + packageInfo.packageName);
+ return null;
+ }
+
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA256");
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ Signature[] signatures = packageInfo.signingInfo.getSigningCertificateHistory();
+ if (signatures == null || signatures.length == 0) {
+ return null;
+ }
+ md.update(signatures[0].toByteArray());
+ return md.digest();
+ }
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1b5b7e8..4e36e3f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -237,6 +237,7 @@
"dreams_flags_lib",
"aconfig_new_storage_flags_lib",
"powerstats_flags_lib",
+ "locksettings_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 556fae3..30f3fd2 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -78,24 +78,11 @@
"file_patterns": ["StorageManagerService\\.java"]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.BinaryTransparencyServiceTest"
- }
- ],
+ "name": "FrameworksServicesTests_binary_transparency",
"file_patterns": ["BinaryTransparencyService\\.java"]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.PinnerServiceTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ],
+ "name": "FrameworksServicesTests_pinner_service",
"file_patterns": ["PinnerService\\.java"]
},
{
@@ -176,15 +163,7 @@
"name": "CtsPackageManagerTestCases"
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.PinnerServiceTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ],
+ "name": "FrameworksServicesTests_pinner_service",
"file_patterns": ["PinnerService\\.java"]
},
{
diff --git a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
index 4da5cfc..9398c7a 100644
--- a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
+++ b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
@@ -34,7 +34,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import android.util.Slog;
@@ -73,7 +72,6 @@
private final LockSettingsInternal mLockSettings;
private final BiometricManager mBiometricManager;
private final KeyguardManager mKeyguardManager;
- private final PowerManager mPowerManager;
private final WindowManagerInternal mWindowManager;
private final UserManagerInternal mUserManager;
@VisibleForTesting
@@ -93,7 +91,6 @@
mBiometricManager = Objects.requireNonNull(
context.getSystemService(BiometricManager.class));
mKeyguardManager = Objects.requireNonNull(context.getSystemService(KeyguardManager.class));
- mPowerManager = Objects.requireNonNull(context.getSystemService(PowerManager.class));
mWindowManager = Objects.requireNonNull(
LocalServices.getService(WindowManagerInternal.class));
mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
@@ -290,9 +287,6 @@
parentUserId);
}
- // Power off the display
- mPowerManager.goToSleep(SystemClock.uptimeMillis());
-
// Lock the device
mWindowManager.lockNow();
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index f5a297b..6fd281e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -685,6 +685,11 @@
// default. Controlled by Settings.Global.FORCE_ENABLE_PSS_PROFILING
volatile boolean mForceEnablePssProfiling = false;
+ // Indicates whether to use ApplicationInfo to determine launched state instead of PM user state
+ // This is a temporary workaround until the trunk-stable flag is pushed to nextfood.
+ // TODO: b/365979852 - remove this workaround when redundant
+ volatile boolean mFlagUseAppInfoNotLaunched = false;
+
/**
* Indicates whether the foreground service background start restriction is enabled for
* caller app that is targeting S+.
@@ -1017,6 +1022,9 @@
private static final Uri FORCE_ENABLE_PSS_PROFILING_URI =
Settings.Global.getUriFor(Settings.Global.FORCE_ENABLE_PSS_PROFILING);
+ private static final Uri ENABLE_USE_APP_INFO_NOT_LAUNCHED_URI =
+ Settings.Global.getUriFor(Settings.Global.ENABLE_USE_APP_INFO_NOT_LAUNCHED);
+
/**
* The threshold to decide if a given association should be dumped into metrics.
*/
@@ -1479,6 +1487,7 @@
false, this);
}
mResolver.registerContentObserver(FORCE_ENABLE_PSS_PROFILING_URI, false, this);
+ mResolver.registerContentObserver(ENABLE_USE_APP_INFO_NOT_LAUNCHED_URI, false, this);
updateConstants();
if (mSystemServerAutomaticHeapDumpEnabled) {
updateEnableAutomaticSystemServerHeapDumps();
@@ -1495,6 +1504,7 @@
updateActivityStartsLoggingEnabled();
updateForegroundServiceStartsLoggingEnabled();
updateForceEnablePssProfiling();
+ updateEnableUseAppInfoNotLaunched();
// Read DropboxRateLimiter params from flags.
mService.initDropboxRateLimiter();
}
@@ -1540,6 +1550,8 @@
updateEnableAutomaticSystemServerHeapDumps();
} else if (FORCE_ENABLE_PSS_PROFILING_URI.equals(uri)) {
updateForceEnablePssProfiling();
+ } else if (ENABLE_USE_APP_INFO_NOT_LAUNCHED_URI.equals(uri)) {
+ updateEnableUseAppInfoNotLaunched();
}
}
@@ -1659,6 +1671,11 @@
Settings.Global.FORCE_ENABLE_PSS_PROFILING, 0) == 1;
}
+ private void updateEnableUseAppInfoNotLaunched() {
+ mFlagUseAppInfoNotLaunched = Settings.Global.getInt(mResolver,
+ Settings.Global.ENABLE_USE_APP_INFO_NOT_LAUNCHED, 0) == 1;
+ }
+
private void updateBackgroundActivityStarts() {
mFlagBackgroundActivityStartsEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -2538,6 +2555,8 @@
pw.print(" OOMADJ_UPDATE_QUICK="); pw.println(OOMADJ_UPDATE_QUICK);
pw.print(" ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION=");
pw.println(mEnableWaitForFinishAttachApplication);
+ pw.print(" FLAG_USE_APP_INFO_NOT_LAUNCHED=");
+ pw.println(mFlagUseAppInfoNotLaunched);
pw.print(" "); pw.print(KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
pw.print("="); pw.println(FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3f4902d..75e9fad 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1018,7 +1018,9 @@
if (Flags.addBatteryUsageStatsSliceAtom()) {
statsManager.setPullAtomCallback(
FrameworkStatsLog.BATTERY_USAGE_STATS_PER_UID,
- null, // use default PullAtomMetadata values
+ new StatsManager.PullAtomMetadata.Builder()
+ .setTimeoutMillis(3_000L)
+ .build(),
DIRECT_EXECUTOR,
pullAtomCallback);
}
@@ -1098,14 +1100,11 @@
DEVICE_CONFIG_NAMESPACE,
MIN_CONSUMED_POWER_THRESHOLD_KEY,
0);
- final long sessionStart = 0;
- final long sessionEnd = System.currentTimeMillis();
final BatteryUsageStatsQuery query =
new BatteryUsageStatsQuery.Builder()
.setMaxStatsAgeMs(0)
.includeProcessStateData()
.includeVirtualUids()
- .aggregateSnapshots(sessionStart, sessionEnd)
.setMinConsumedPowerThreshold(minConsumedPowerThreshold)
.build();
bus = getBatteryUsageStats(List.of(query)).get(0);
@@ -1834,7 +1833,7 @@
@Override
@EnforcePermission(UPDATE_DEVICE_STATS)
- public void noteScreenState(final int state) {
+ public void noteScreenState(final int displayId, final int state, final int reason) {
super.noteScreenState_enforcePermission();
synchronized (mLock) {
@@ -1844,7 +1843,8 @@
mHandler.post(() -> {
if (DBG) Slog.d(TAG, "begin noteScreenState");
synchronized (mStats) {
- mStats.noteScreenStateLocked(0, state, elapsedRealtime, uptime, currentTime);
+ mStats.noteScreenStateLocked(
+ displayId, state, reason, elapsedRealtime, uptime, currentTime);
}
if (DBG) Slog.d(TAG, "end noteScreenState");
});
@@ -1854,7 +1854,7 @@
@Override
@EnforcePermission(UPDATE_DEVICE_STATS)
- public void noteScreenBrightness(final int brightness) {
+ public void noteScreenBrightness(final int displayId, final int brightness) {
super.noteScreenBrightness_enforcePermission();
synchronized (mLock) {
@@ -1862,7 +1862,8 @@
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
synchronized (mStats) {
- mStats.noteScreenBrightnessLocked(0, brightness, elapsedRealtime, uptime);
+ mStats.noteScreenBrightnessLocked(
+ displayId, brightness, elapsedRealtime, uptime);
}
});
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4898f10..cb918a0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3398,7 +3398,8 @@
// Check if we should mark the processrecord for first launch after force-stopping
if (wasStopped) {
boolean wasEverLaunched = false;
- if (android.app.Flags.useAppInfoNotLaunched()) {
+ if (android.app.Flags.useAppInfoNotLaunched()
+ || mService.mConstants.mFlagUseAppInfoNotLaunched) {
wasEverLaunched = !info.isNotLaunched();
} else {
try {
@@ -3419,7 +3420,8 @@
: STOPPED_STATE_FIRST_LAUNCH;
r.getWindowProcessController().setStoppedState(stoppedState);
} else {
- if (android.app.Flags.useAppInfoNotLaunched()) {
+ if (android.app.Flags.useAppInfoNotLaunched()
+ || mService.mConstants.mFlagUseAppInfoNotLaunched) {
// If it was launched before, then it must be a force-stop
r.setWasForceStopped(wasEverLaunched);
} else {
@@ -3769,7 +3771,7 @@
boolean hasActivity = false;
int connUid = 0;
int connGroup = 0;
- while (i >= bottomI) {
+ while (subProc.info.uid != uid) {
mLruProcesses.remove(i);
mLruProcesses.add(endIndex, subProc);
if (DEBUG_LRU) Slog.d(TAG_LRU,
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 439bca0..a13ce65 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -370,6 +370,13 @@
String propertyName = "next_boot." + makeAconfigFlagPropertyName(
actualNamespace, actualFlagName);
+ if (Flags.supportLocalOverridesSysprops()) {
+ // Don't propagate if there is a local override.
+ String overrideName = actualNamespace + ":" + actualFlagName;
+ if (DeviceConfig.getProperty(NAMESPACE_LOCAL_OVERRIDES, overrideName) != null) {
+ continue;
+ }
+ }
setProperty(propertyName, flagValue);
}
@@ -388,6 +395,42 @@
if (enableAconfigStorageDaemon()) {
setLocalOverridesInNewStorage(properties);
}
+
+ if (Flags.supportLocalOverridesSysprops()) {
+ String overridesNamespace = properties.getNamespace();
+ for (String key : properties.getKeyset()) {
+ String realNamespace = key.split(":")[0];
+ String realFlagName = key.split(":")[1];
+ String aconfigPropertyName =
+ makeAconfigFlagPropertyName(realNamespace, realFlagName);
+ if (aconfigPropertyName == null) {
+ logErr("unable to construct system property for " + realNamespace + "/"
+ + key);
+ return;
+ }
+
+ if (properties.getString(key, null) == null) {
+ String deviceConfigValue =
+ DeviceConfig.getProperty(realNamespace, realFlagName);
+ String stagedDeviceConfigValue =
+ DeviceConfig.getProperty(NAMESPACE_REBOOT_STAGING,
+ realNamespace + "*" + realFlagName);
+
+ setProperty(aconfigPropertyName, deviceConfigValue);
+ if (stagedDeviceConfigValue == null) {
+ setProperty("next_boot." + aconfigPropertyName, deviceConfigValue);
+ } else {
+ setProperty("next_boot." + aconfigPropertyName, stagedDeviceConfigValue);
+ }
+ } else {
+ // Otherwise, propagate the override to sysprops.
+ setProperty(aconfigPropertyName, properties.getString(key, null));
+ // If there's a staged value, make sure it's the override value.
+ setProperty("next_boot." + aconfigPropertyName,
+ properties.getString(key, null));
+ }
+ }
+ }
});
}
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 6e8eb7d..ab5e2d0 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -94,12 +94,7 @@
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.am."
- }
- ]
+ "name": "FrameworksServicesTests_android_server_am"
},
{
"name": "CtsAppDataIsolationHostTestCases"
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 430be03..314664b 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -110,7 +110,8 @@
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
- AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
+ AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
+ DiscreteRegistry.ACCESS_TYPE_NOTE_OP);
}
/**
@@ -254,7 +255,7 @@
if (isStarted) {
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
- attributionFlags, attributionChainId);
+ attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP);
}
}
@@ -290,12 +291,17 @@
* stopping in the HistoricalRegistry, but does not delete it.
*
* @param triggeredByUidStateChange If {@code true}, then this method operates as usual, except
- * that {@link AppOpsService#mActiveWatchers} will not be notified. This is currently only
- * used in {@link #onUidStateChanged(int)}, for the purpose of restarting (i.e.,
- * finishing then immediately starting again in the new uid state) the AttributedOp. In this
- * case, the caller is responsible for guaranteeing that either the AttributedOp is started
- * again or all {@link AppOpsService#mActiveWatchers} are notified that the AttributedOp is
- * finished.
+ * that {@link AppOpsService#mActiveWatchers} will not be
+ * notified. This is currently only
+ * used in {@link #onUidStateChanged(int)}, for the purpose of
+ * restarting (i.e.,
+ * finishing then immediately starting again in the new uid
+ * state) the AttributedOp. In this
+ * case, the caller is responsible for guaranteeing that either
+ * the AttributedOp is started
+ * again or all {@link AppOpsService#mActiveWatchers} are
+ * notified that the AttributedOp is
+ * finished.
*/
@SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
private void finishOrPause(@NonNull IBinder clientId, boolean triggeredByUidStateChange,
@@ -335,7 +341,9 @@
mAppOpsService.mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, event.getUidState(),
event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration(),
- event.getAttributionFlags(), event.getAttributionChainId());
+ event.getAttributionFlags(), event.getAttributionChainId(),
+ isPausing ? DiscreteRegistry.ACCESS_TYPE_PAUSE_OP
+ : DiscreteRegistry.ACCESS_TYPE_FINISH_OP);
if (!isPausing) {
mAppOpsService.mInProgressStartOpEventPool.release(event);
@@ -443,7 +451,7 @@
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, event.getUidState(),
event.getFlags(), startTime, event.getAttributionFlags(),
- event.getAttributionChainId());
+ event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP);
if (shouldSendActive) {
mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
parent.packageName, tag, event.getVirtualDeviceId(), true,
@@ -864,12 +872,12 @@
}
InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
- @Nullable String attributionTag, int virtualDeviceId, @NonNull Runnable onDeath,
+ @Nullable String attributionTag, int virtualDeviceId, @NonNull Runnable onDeath,
int proxyUid, @Nullable String proxyPackageName,
@Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
- @AppOpsManager.UidState int uidState,
- @AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags
- int attributionFlags, int attributionChainId) throws RemoteException {
+ @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
+ @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId)
+ throws RemoteException {
InProgressStartOpEvent recycled = acquire();
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 2ce4623..7f161f6 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -32,13 +32,23 @@
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
+import static android.app.AppOpsManager.OP_PROCESS_OUTGOING_CALLS;
+import static android.app.AppOpsManager.OP_READ_ICC_SMS;
+import static android.app.AppOpsManager.OP_READ_SMS;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RESERVED_FOR_TESTING;
+import static android.app.AppOpsManager.OP_SEND_SMS;
+import static android.app.AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import static android.app.AppOpsManager.OP_WRITE_ICC_SMS;
+import static android.app.AppOpsManager.OP_WRITE_SMS;
import static android.app.AppOpsManager.flagsToString;
import static android.app.AppOpsManager.getUidStateName;
import static android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
@@ -46,6 +56,7 @@
import static java.lang.Long.min;
import static java.lang.Math.max;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -62,6 +73,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -72,6 +84,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
@@ -125,7 +139,6 @@
* relies on {@link HistoricalRegistry} for controlling that no calls are allowed until then. All
* outside calls are going through {@link HistoricalRegistry}, where
* {@link HistoricalRegistry#isPersistenceInitializedMLocked()} check is done.
- *
*/
final class DiscreteRegistry {
@@ -142,11 +155,40 @@
+ OP_PHONE_CALL_MICROPHONE + "," + OP_PHONE_CALL_CAMERA + ","
+ OP_RECEIVE_AMBIENT_TRIGGER_AUDIO + "," + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
+ "," + OP_RESERVED_FOR_TESTING;
+ private static final int[] sDiscreteOpsToLog =
+ new int[]{OP_FINE_LOCATION, OP_COARSE_LOCATION, OP_EMERGENCY_LOCATION, OP_CAMERA,
+ OP_RECORD_AUDIO, OP_PHONE_CALL_MICROPHONE, OP_PHONE_CALL_CAMERA,
+ OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, OP_READ_SMS,
+ OP_WRITE_SMS, OP_SEND_SMS, OP_READ_ICC_SMS, OP_WRITE_ICC_SMS,
+ OP_SMS_FINANCIAL_TRANSACTIONS, OP_SYSTEM_ALERT_WINDOW, OP_MONITOR_LOCATION,
+ OP_MONITOR_HIGH_POWER_LOCATION, OP_PROCESS_OUTGOING_CALLS,
+ };
private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION =
Duration.ofMinutes(1).toMillis();
+ static final int ACCESS_TYPE_NOTE_OP =
+ FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__NOTE_OP;
+ static final int ACCESS_TYPE_START_OP =
+ FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__START_OP;
+ static final int ACCESS_TYPE_FINISH_OP =
+ FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__FINISH_OP;
+ static final int ACCESS_TYPE_PAUSE_OP =
+ FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__PAUSE_OP;
+ static final int ACCESS_TYPE_RESUME_OP =
+ FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__RESUME_OP;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ACCESS_TYPE_"}, value = {
+ ACCESS_TYPE_NOTE_OP,
+ ACCESS_TYPE_START_OP,
+ ACCESS_TYPE_FINISH_OP,
+ ACCESS_TYPE_PAUSE_OP,
+ ACCESS_TYPE_RESUME_OP
+ })
+ public @interface AccessType {}
+
private static long sDiscreteHistoryCutoff;
private static long sDiscreteHistoryQuantization;
private static int[] sDiscreteOps;
@@ -255,7 +297,23 @@
void recordDiscreteAccess(int uid, String packageName, @NonNull String deviceId, int op,
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
- @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+ @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
+ @AccessType int accessType) {
+ if (shouldLogAccess(op)) {
+ int firstChar = 0;
+ if (attributionTag != null && attributionTag.startsWith(packageName)) {
+ firstChar = packageName.length();
+ if (firstChar < attributionTag.length() && attributionTag.charAt(firstChar)
+ == '.') {
+ firstChar++;
+ }
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_OP_ACCESS_TRACKED, uid, op, accessType,
+ uidState, flags, attributionFlags,
+ attributionTag == null ? null : attributionTag.substring(firstChar),
+ attributionChainId);
+ }
+
if (!isDiscreteOp(op, flags)) {
return;
}
@@ -388,7 +446,7 @@
if (event == null
|| event.mAttributionChainId == ATTRIBUTION_CHAIN_ID_NONE
|| (event.mAttributionFlags & ATTRIBUTION_FLAG_TRUSTED)
- == 0) {
+ == 0) {
continue;
}
@@ -1523,6 +1581,11 @@
return true;
}
+ private static boolean shouldLogAccess(int op) {
+ return Flags.appopAccessTrackingLoggingEnabled()
+ && ArrayUtils.contains(sDiscreteOpsToLog, op);
+ }
+
private static long discretizeTimeStamp(long timeStamp) {
return timeStamp / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;
@@ -1530,7 +1593,7 @@
private static long discretizeDuration(long duration) {
return duration == -1 ? -1 : (duration + sDiscreteHistoryQuantization - 1)
- / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;
+ / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;
}
void setDebugMode(boolean debugMode) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index fffb108..6b02538 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -474,7 +474,8 @@
void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
@NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
@OpFlags int flags, long accessTime,
- @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+ @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
+ @DiscreteRegistry.AccessType int accessType) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -487,7 +488,7 @@
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
attributionTag, flags, uidState, accessTime, -1, attributionFlags,
- attributionChainId);
+ attributionChainId, accessType);
}
}
}
@@ -510,7 +511,8 @@
void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
@NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
@OpFlags int flags, long eventStartTime, long increment,
- @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+ @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
+ @DiscreteRegistry.AccessType int accessType) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -522,7 +524,7 @@
attributionTag, uidState, flags, increment);
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
attributionTag, flags, uidState, eventStartTime, increment,
- attributionFlags, attributionChainId);
+ attributionFlags, attributionChainId, accessType);
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6daf0d0..c3d09bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9211,7 +9211,7 @@
index = 1;
}
- if (replaceStreamBtSco()) {
+ if (replaceStreamBtSco() && index != 0) {
index = (int) (mIndexMin + (index * 10 - mIndexMin) / getIndexStepFactor() + 5)
/ 10;
}
diff --git a/services/core/java/com/android/server/biometrics/biometrics.aconfig b/services/core/java/com/android/server/biometrics/biometrics.aconfig
index b2e95aa..d3da8dd 100644
--- a/services/core/java/com/android/server/biometrics/biometrics.aconfig
+++ b/services/core/java/com/android/server/biometrics/biometrics.aconfig
@@ -24,3 +24,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "set_ignore_speed_up"
+ namespace: "biometrics_framework"
+ description: "This flag controls whether setIgnoreDisplayTouches is called directly on session from FingerprintProvider"
+ bug: "359289274"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 8195efe..456591c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -791,7 +791,17 @@
@Override
public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) {
- mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+ if (Flags.setIgnoreSpeedUp()) {
+ try {
+ mFingerprintSensors.get(
+ sensorId).getLazySession().get().getSession().setIgnoreDisplayTouches(
+ ignoreTouches);
+ Slog.d(getTag(), "setIgnoreDisplayTouches set to " + ignoreTouches);
+ } catch (Exception e) {
+ Slog.w(getTag(), "setIgnore failed", e);
+ }
+ } else {
+ mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
requestId, (client) -> {
if (!(client instanceof Udfps)) {
Slog.e(getTag(),
@@ -800,6 +810,7 @@
}
((Udfps) client).setIgnoreDisplayTouches(ignoreTouches);
});
+ }
}
@Override
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java
index 984ad1d..a68451a 100644
--- a/services/core/java/com/android/server/cpu/CpuInfoReader.java
+++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java
@@ -40,6 +40,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -80,13 +81,14 @@
/** package **/ @interface CpusetCategory{}
// TODO(b/242722241): Protect updatable variables with a local lock.
- private final File mCpusetDir;
private final long mMinReadIntervalMillis;
private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
private final SparseArray<File> mCpuFreqPolicyDirsById = new SparseArray<>();
private final SparseArray<StaticPolicyInfo> mStaticPolicyInfoById = new SparseArray<>();
private final SparseArray<LongSparseLongArray> mTimeInStateByPolicyId = new SparseArray<>();
+ private final AtomicBoolean mShouldReadCpusetCategories;
+ private File mCpusetDir;
private File mCpuFreqDir;
private File mProcStatFile;
private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
@@ -106,10 +108,13 @@
mCpuFreqDir = cpuFreqDir;
mProcStatFile = procStatFile;
mMinReadIntervalMillis = minReadIntervalMillis;
+ mShouldReadCpusetCategories = new AtomicBoolean(true);
}
/**
* Initializes CpuInfoReader and returns a boolean to indicate whether the reader is enabled.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
public boolean init() {
if (mCpuFreqPolicyDirsById.size() > 0) {
@@ -139,8 +144,7 @@
Slogf.e(TAG, "Missing proc stat file at %s", mProcStatFile.getAbsolutePath());
return false;
}
- readCpusetCategories();
- if (mCpusetCategoriesByCpus.size() == 0) {
+ if (!readCpusetCategories()) {
Slogf.e(TAG, "Failed to read cpuset information from %s", mCpusetDir.getAbsolutePath());
return false;
}
@@ -163,10 +167,19 @@
return true;
}
+ public void stopPeriodicCpusetReading() {
+ mShouldReadCpusetCategories.set(false);
+ if (!readCpusetCategories()) {
+ Slogf.e(TAG, "Failed to read cpuset information from %s",
+ mCpusetDir.getAbsolutePath());
+ mIsEnabled = false;
+ }
+ }
+
/**
* Reads CPU information from proc and sys fs files exposed by the Kernel.
*
- * @return SparseArray keyed by CPU core ID; {@code null} on error or when disabled.
+ * <p>Returns SparseArray keyed by CPU core ID; {@code null} on error or when disabled.
*/
@Nullable
public SparseArray<CpuInfo> readCpuInfos() {
@@ -183,6 +196,12 @@
}
mLastReadUptimeMillis = uptimeMillis;
mLastReadCpuInfos = null;
+ if (mShouldReadCpusetCategories.get() && !readCpusetCategories()) {
+ Slogf.e(TAG, "Failed to read cpuset information from %s",
+ mCpusetDir.getAbsolutePath());
+ mIsEnabled = false;
+ return null;
+ }
SparseArray<CpuUsageStats> cpuUsageStatsByCpus = readLatestCpuUsageStats();
if (cpuUsageStatsByCpus == null || cpuUsageStatsByCpus.size() == 0) {
Slogf.e(TAG, "Failed to read latest CPU usage stats");
@@ -324,7 +343,7 @@
/**
* Sets the CPU frequency for testing.
*
- * <p>Return {@code true} on success. Otherwise, returns {@code false}.
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
@VisibleForTesting
boolean setCpuFreqDir(File cpuFreqDir) {
@@ -354,7 +373,7 @@
/**
* Sets the proc stat file for testing.
*
- * <p>Return true on success. Otherwise, returns false.
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
@VisibleForTesting
boolean setProcStatFile(File procStatFile) {
@@ -366,6 +385,21 @@
return true;
}
+ /**
+ * Set the cpuset directory for testing.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
+ */
+ @VisibleForTesting
+ boolean setCpusetDir(File cpusetDir) {
+ if (!cpusetDir.exists() && !cpusetDir.isDirectory()) {
+ Slogf.e(TAG, "Missing or invalid cpuset directory at %s", cpusetDir.getAbsolutePath());
+ return false;
+ }
+ mCpusetDir = cpusetDir;
+ return true;
+ }
+
private void populateCpuFreqPolicyDirsById(File[] policyDirs) {
mCpuFreqPolicyDirsById.clear();
for (int i = 0; i < policyDirs.length; i++) {
@@ -381,12 +415,27 @@
}
}
- private void readCpusetCategories() {
+ /**
+ * Reads cpuset categories by CPU.
+ *
+ * <p>The cpusets are read from the cpuset category specific directories
+ * under the /dev/cpuset directory. The cpuset categories are subject to change at any point
+ * during system bootup, as determined by the init rules specified within the init.rc files.
+ * Therefore, it's necessary to read the cpuset categories each time before accessing CPU usage
+ * statistics until the system boot completes. Once the boot is complete, the latest changes to
+ * the cpuset categories will take a few seconds to propagate. Thus, on boot complete,
+ * the periodic reading is stopped with a delay of
+ * {@link CpuMonitorService#STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS}.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
+ */
+ private boolean readCpusetCategories() {
File[] cpusetDirs = mCpusetDir.listFiles(File::isDirectory);
if (cpusetDirs == null) {
Slogf.e(TAG, "Missing cpuset directories at %s", mCpusetDir.getAbsolutePath());
- return;
+ return false;
}
+ mCpusetCategoriesByCpus.clear();
for (int i = 0; i < cpusetDirs.length; i++) {
File dir = cpusetDirs[i];
@CpusetCategory int cpusetCategory;
@@ -418,6 +467,7 @@
}
}
}
+ return mCpusetCategoriesByCpus.size() > 0;
}
private void readStaticPolicyInfo() {
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index 7ea2c1b..88ff7e4 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -22,6 +22,7 @@
import static com.android.server.cpu.CpuAvailabilityMonitoringConfig.CPUSET_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import android.annotation.Nullable;
import android.content.Context;
@@ -82,6 +83,15 @@
// frequently. Should this duration be increased as well when this happens?
private static final long LATEST_AVAILABILITY_DURATION_MILLISECONDS =
TimeUnit.SECONDS.toMillis(30);
+ /**
+ * Delay to stop the periodic cpuset reading after boot complete.
+ *
+ * Device specific implementations can update cpuset on boot complete. This may take
+ * a few seconds to propagate. So, wait for a few minutes before stopping the periodic cpuset
+ * reading.
+ */
+ private static final long STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS =
+ TimeUnit.MINUTES.toMillis(2);
private final Context mContext;
private final HandlerThread mHandlerThread;
@@ -90,6 +100,7 @@
private final long mNormalMonitoringIntervalMillis;
private final long mDebugMonitoringIntervalMillis;
private final long mLatestAvailabilityDurationMillis;
+ private final long mStopPeriodicCpusetReadingDelayMillis;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final SparseArrayMap<CpuMonitorInternal.CpuAvailabilityCallback,
@@ -153,13 +164,15 @@
this(context, new CpuInfoReader(), new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, /* allowIo= */ true),
Build.IS_USERDEBUG || Build.IS_ENG, NORMAL_MONITORING_INTERVAL_MILLISECONDS,
- DEBUG_MONITORING_INTERVAL_MILLISECONDS, LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ DEBUG_MONITORING_INTERVAL_MILLISECONDS, LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
}
@VisibleForTesting
CpuMonitorService(Context context, CpuInfoReader cpuInfoReader, HandlerThread handlerThread,
boolean shouldDebugMonitor, long normalMonitoringIntervalMillis,
- long debugMonitoringIntervalMillis, long latestAvailabilityDurationMillis) {
+ long debugMonitoringIntervalMillis, long latestAvailabilityDurationMillis,
+ long stopPeriodicCpusetReadingDelayMillis) {
super(context);
mContext = context;
mHandlerThread = handlerThread;
@@ -167,6 +180,7 @@
mNormalMonitoringIntervalMillis = normalMonitoringIntervalMillis;
mDebugMonitoringIntervalMillis = debugMonitoringIntervalMillis;
mLatestAvailabilityDurationMillis = latestAvailabilityDurationMillis;
+ mStopPeriodicCpusetReadingDelayMillis = stopPeriodicCpusetReadingDelayMillis;
mCpuInfoReader = cpuInfoReader;
mCpusetInfosByCpuset = new SparseArray<>(2);
mCpusetInfosByCpuset.append(CPUSET_ALL, new CpusetInfo(CPUSET_ALL));
@@ -200,6 +214,16 @@
}
}
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase != PHASE_BOOT_COMPLETED) {
+ return;
+ }
+ Slogf.i(TAG, "Stopping periodic cpuset reading on boot complete");
+ mHandler.postDelayed(() -> mCpuInfoReader.stopPeriodicCpusetReading(),
+ mStopPeriodicCpusetReadingDelayMillis);
+ }
+
@VisibleForTesting
long getCurrentMonitoringIntervalMillis() {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
index 615db34..537fb325 100644
--- a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
+++ b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
@@ -1,4 +1,9 @@
{
+ "presubmit": [
+ {
+ "name": "CrashRecoveryModuleTests"
+ }
+ ],
"postsubmit": [
{
"name": "FrameworksMockingServicesTests",
@@ -7,9 +12,6 @@
"include-filter": "com.android.server.RescuePartyTest"
}
]
- },
- {
- "name": "CrashRecoveryModuleTests"
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index d78fdfa..dc263c5 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -796,7 +796,6 @@
private DensityMapping mDensityMapping;
private String mLoadedFrom = null;
-
// Represents the auto-brightness brightening light debounce.
private long mAutoBrightnessBrighteningLightDebounce =
INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE;
@@ -1686,7 +1685,6 @@
+ "\n"
+ "mLuxThrottlingData=" + mLuxThrottlingData
+ ", mHbmData=" + mHbmData
-
+ ", mThermalBrightnessThrottlingDataMapByThrottlingId="
+ mThermalBrightnessThrottlingDataMapByThrottlingId
+ "\n"
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 9644b1d..3c2167e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -4779,6 +4779,18 @@
token, displayId, modeIds);
}
+ @Override // Binder call
+ public float getHighestHdrSdrRatio(int displayId) {
+ DisplayDeviceConfig ddc =
+ mDisplayDeviceConfigProvider.getDisplayDeviceConfig(displayId);
+ if (ddc == null) {
+ throw new IllegalArgumentException(
+ "Display ID does not have a config: " + displayId);
+ }
+ return ddc.getHdrBrightnessData() != null
+ ? ddc.getHdrBrightnessData().highestHdrSdrRatio : 1;
+ }
+
@EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
@Override // Binder call
public float[] getDozeBrightnessSensorValueToBrightness(int displayId) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index c3faec0..04573f4 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -536,7 +536,9 @@
mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
- if (mDisplayId == Display.DEFAULT_DISPLAY) {
+ if (flags.isBatteryStatsEnabledForAllDisplays()) {
+ mBatteryStats = BatteryStatsService.getService();
+ } else if (mDisplayId == Display.DEFAULT_DISPLAY) {
mBatteryStats = BatteryStatsService.getService();
} else {
mBatteryStats = null;
@@ -2791,8 +2793,7 @@
screenState, mDisplayStatsId, reason);
if (mBatteryStats != null) {
try {
- // TODO(multi-display): make this multi-display
- mBatteryStats.noteScreenState(screenState);
+ mBatteryStats.noteScreenState(mDisplayId, screenState, reason);
} catch (RemoteException e) {
// same process
}
@@ -2807,7 +2808,7 @@
int brightnessInt = mFlags.isBrightnessIntRangeUserPerceptionEnabled()
? BrightnessSynchronizer.brightnessFloatToIntSetting(mContext, brightness)
: BrightnessSynchronizer.brightnessFloatToInt(brightness);
- mBatteryStats.noteScreenBrightness(brightnessInt);
+ mBatteryStats.noteScreenBrightness(mDisplayId, brightnessInt);
} catch (RemoteException e) {
// same process
}
diff --git a/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java b/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
index 5b4e8d5..a60434b 100644
--- a/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
+++ b/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
@@ -60,4 +60,23 @@
return Spline.createSpline(x, y);
}
+
+ /**
+ * Get the highest HDR/SDR ratio from the given map.
+ * @param points The map of brightness values to HDR/SDR ratios
+ * @param extractor Used to retrieve the ratio from the map element
+ * @return The highest HDR/SDR ratio
+ * @param <T> The type of the map elements
+ */
+ public static <T> float getHighestHdrSdrRatio(List<T> points,
+ Function<T, BigDecimal> extractor) {
+ float highestRatio = 1;
+ for (T point : points) {
+ float ratio = extractor.apply(point).floatValue();
+ if (ratio > highestRatio) {
+ highestRatio = ratio;
+ }
+ }
+ return highestRatio;
+ }
}
diff --git a/services/core/java/com/android/server/display/config/HdrBrightnessData.java b/services/core/java/com/android/server/display/config/HdrBrightnessData.java
index ef4a798..751ab30 100644
--- a/services/core/java/com/android/server/display/config/HdrBrightnessData.java
+++ b/services/core/java/com/android/server/display/config/HdrBrightnessData.java
@@ -126,13 +126,16 @@
@Nullable
public final Spline sdrToHdrRatioSpline;
+ public final float highestHdrSdrRatio;
+
@VisibleForTesting
public HdrBrightnessData(Map<Float, Float> maxBrightnessLimits,
long brightnessIncreaseDebounceMillis, float screenBrightnessRampIncrease,
long brightnessDecreaseDebounceMillis, float screenBrightnessRampDecrease,
float hbmTransitionPoint,
float minimumHdrPercentOfScreenForNbm, float minimumHdrPercentOfScreenForHbm,
- boolean allowInLowPowerMode, @Nullable Spline sdrToHdrRatioSpline) {
+ boolean allowInLowPowerMode, @Nullable Spline sdrToHdrRatioSpline,
+ float highestHdrSdrRatio) {
this.maxBrightnessLimits = maxBrightnessLimits;
this.brightnessIncreaseDebounceMillis = brightnessIncreaseDebounceMillis;
this.screenBrightnessRampIncrease = screenBrightnessRampIncrease;
@@ -143,6 +146,7 @@
this.minimumHdrPercentOfScreenForHbm = minimumHdrPercentOfScreenForHbm;
this.allowInLowPowerMode = allowInLowPowerMode;
this.sdrToHdrRatioSpline = sdrToHdrRatioSpline;
+ this.highestHdrSdrRatio = highestHdrSdrRatio;
}
@Override
@@ -158,6 +162,7 @@
+ ", minimumHdrPercentOfScreenForHbm: " + minimumHdrPercentOfScreenForHbm
+ ", allowInLowPowerMode: " + allowInLowPowerMode
+ ", sdrToHdrRatioSpline: " + sdrToHdrRatioSpline
+ + ", highestHdrSdrRatio: " + highestHdrSdrRatio
+ "} ";
}
@@ -198,7 +203,9 @@
hdrConfig.getScreenBrightnessRampDecrease().floatValue(),
getTransitionPoint(hbmConfig, transitionPointProvider),
minHdrPercentForNbm, minHdrPercentForHbm, hdrConfig.getAllowInLowPowerMode(),
- getSdrHdrRatioSpline(hdrConfig, config.getHighBrightnessMode()));
+ getSdrHdrRatioSpline(hdrConfig, config.getHighBrightnessMode()),
+ getHighestSdrHdrRatio(hdrConfig, config.getHighBrightnessMode())
+ );
}
private static float getTransitionPoint(@Nullable HighBrightnessMode hbm,
@@ -222,7 +229,8 @@
0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
getTransitionPoint(hbm, transitionPointProvider),
- fallbackPercent, fallbackPercent, false, fallbackSpline);
+ fallbackPercent, fallbackPercent, false, fallbackSpline,
+ getFallbackHighestSdrHdrRatio(hbm));
}
private static float getFallbackHdrPercent(HighBrightnessMode hbm) {
@@ -251,4 +259,23 @@
return DisplayDeviceConfigUtils.createSpline(fallbackMap.getPoint(),
SdrHdrRatioPoint::getSdrNits, SdrHdrRatioPoint::getHdrRatio);
}
+
+ private static float getHighestSdrHdrRatio(HdrBrightnessConfig hdrConfig,
+ HighBrightnessMode hbm) {
+ NonNegativeFloatToFloatMap sdrHdrRatioMap = hdrConfig.getSdrHdrRatioMap();
+ if (sdrHdrRatioMap == null) {
+ return getFallbackHighestSdrHdrRatio(hbm);
+ }
+ return DisplayDeviceConfigUtils.getHighestHdrSdrRatio(sdrHdrRatioMap.getPoint(),
+ NonNegativeFloatToFloatPoint::getSecond);
+ }
+
+ private static float getFallbackHighestSdrHdrRatio(HighBrightnessMode hbm) {
+ SdrHdrRatioMap fallbackMap = hbm != null ? hbm.getSdrHdrRatioMap_all() : null;
+ if (fallbackMap == null) {
+ return 1;
+ }
+ return DisplayDeviceConfigUtils.getHighestHdrSdrRatio(fallbackMap.getPoint(),
+ SdrHdrRatioPoint::getHdrRatio);
+ }
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 69b67c8..f600e7f 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -200,6 +200,11 @@
Flags::normalBrightnessForDozeParameter
);
+ private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState(
+ Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
+ Flags::enableBatteryStatsForAllDisplays
+ );
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -415,6 +420,14 @@
}
/**
+ * @return {@code true} if battery stats is enabled for all displays, not just the primary
+ * display.
+ */
+ public boolean isBatteryStatsEnabledForAllDisplays() {
+ return mEnableBatteryStatsForAllDisplays.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -456,6 +469,7 @@
pw.println(" " + mNewHdrBrightnessModifier);
pw.println(" " + mNormalBrightnessForDozeParameter);
pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
+ pw.println(" " + mEnableBatteryStatsForAllDisplays);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index da5063a..9968ba5 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -246,6 +246,14 @@
}
flag {
+ name: "highest_hdr_sdr_ratio_api"
+ namespace: "display_manager"
+ description: "Feature flag for an API to get the highest defined HDR/SDR ratio for a display."
+ bug: "335181559"
+ is_fixed_read_only: true
+}
+
+flag {
name: "doze_brightness_float"
namespace: "display_manager"
description: "Define doze brightness in the float scale [0, 1]."
@@ -341,3 +349,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_battery_stats_for_all_displays"
+ namespace: "display_manager"
+ description: "Flag to enable battery stats for all displays."
+ bug: "366112793"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/TEST_MAPPING b/services/core/java/com/android/server/hdmi/TEST_MAPPING
index 1c85c7f..d116087d 100644
--- a/services/core/java/com/android/server/hdmi/TEST_MAPPING
+++ b/services/core/java/com/android/server/hdmi/TEST_MAPPING
@@ -6,15 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.hdmi"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_android_server_hdmi"
}
],
// Postsubmit tests for TV devices
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index dfcea9f..ca8ae6e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -52,6 +52,7 @@
import android.hardware.input.IInputManager;
import android.hardware.input.IInputSensorEventListener;
import android.hardware.input.IKeyGestureEventListener;
+import android.hardware.input.IKeyGestureHandler;
import android.hardware.input.IKeyboardBacklightListener;
import android.hardware.input.IStickyModifierStateListener;
import android.hardware.input.ITabletModeChangedListener;
@@ -164,7 +165,6 @@
private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
private static final int MSG_RELOAD_DEVICE_ALIASES = 2;
private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 3;
- private static final int MSG_KEY_GESTURE_COMPLETED = 4;
private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
private static final AdditionalDisplayInputProperties
@@ -476,7 +476,7 @@
injector.getLooper(), injector.getUEventManager())
: new KeyboardBacklightControllerInterface() {};
mStickyModifierStateController = new StickyModifierStateController();
- mKeyGestureController = new KeyGestureController();
+ mKeyGestureController = new KeyGestureController(mContext, injector.getLooper());
mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(),
mNative);
mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
@@ -2458,6 +2458,11 @@
// Native callback.
@SuppressWarnings("unused")
private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+ // TODO(b/358569822): Move shortcut trigger logic from PWM to KeyGestureController
+ long value = mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags);
+ if (value != 0) { // If key is consumed (i.e. non-zero value)
+ return value;
+ }
return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
}
@@ -2763,33 +2768,38 @@
@Override
@PermissionManuallyEnforced
- public void registerKeyGestureEventListener(
- @NonNull IKeyGestureEventListener listener) {
+ public void registerKeyGestureEventListener(@NonNull IKeyGestureEventListener listener) {
enforceManageKeyGesturePermission();
Objects.requireNonNull(listener);
- mKeyGestureController.registerKeyGestureEventListener(listener,
- Binder.getCallingPid());
+ mKeyGestureController.registerKeyGestureEventListener(listener, Binder.getCallingPid());
}
@Override
@PermissionManuallyEnforced
- public void unregisterKeyGestureEventListener(
- @NonNull IKeyGestureEventListener listener) {
+ public void unregisterKeyGestureEventListener(@NonNull IKeyGestureEventListener listener) {
enforceManageKeyGesturePermission();
Objects.requireNonNull(listener);
- mKeyGestureController.unregisterKeyGestureEventListener(listener,
- Binder.getCallingPid());
+ mKeyGestureController.unregisterKeyGestureEventListener(listener, Binder.getCallingPid());
}
- private void handleKeyGestureCompleted(KeyGestureEvent event) {
- InputDevice device = getInputDevice(event.getDeviceId());
- if (device == null || device.isVirtual()) {
- return;
- }
- KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event);
- mKeyGestureController.onKeyGestureEvent(event);
+ @Override
+ @PermissionManuallyEnforced
+ public void registerKeyGestureHandler(@NonNull IKeyGestureHandler handler) {
+ enforceManageKeyGesturePermission();
+
+ Objects.requireNonNull(handler);
+ mKeyGestureController.registerKeyGestureHandler(handler, Binder.getCallingPid());
+ }
+
+ @Override
+ @PermissionManuallyEnforced
+ public void unregisterKeyGestureHandler(@NonNull IKeyGestureHandler handler) {
+ enforceManageKeyGesturePermission();
+
+ Objects.requireNonNull(handler);
+ mKeyGestureController.unregisterKeyGestureHandler(handler, Binder.getCallingPid());
}
/**
@@ -2960,9 +2970,6 @@
boolean inTabletMode = (boolean) args.arg1;
deliverTabletModeChanged(whenNanos, inTabletMode);
break;
- case MSG_KEY_GESTURE_COMPLETED:
- KeyGestureEvent event = (KeyGestureEvent) msg.obj;
- handleKeyGestureCompleted(event);
}
}
}
@@ -3292,9 +3299,8 @@
@Override
public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int gestureType) {
- mHandler.obtainMessage(MSG_KEY_GESTURE_COMPLETED,
- new KeyGestureEvent(deviceId, keycodes, modifierState,
- gestureType)).sendToTarget();
+ mKeyGestureController.notifyKeyGestureCompleted(deviceId, keycodes, modifierState,
+ gestureType);
}
}
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 674d3c4..bfdb1c1 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -17,15 +17,32 @@
package com.android.server.input;
import android.annotation.BinderThread;
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.input.AidlKeyGestureEvent;
import android.hardware.input.IKeyGestureEventListener;
+import android.hardware.input.IKeyGestureHandler;
+import android.hardware.input.InputManager;
import android.hardware.input.KeyGestureEvent;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.Display;
+import android.view.InputDevice;
+import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.TreeMap;
/**
* A thread-safe component of {@link InputManagerService} responsible for managing callbacks when a
@@ -39,12 +56,101 @@
// 'adb shell setprop log.tag.KeyGestureController DEBUG' (requires restart)
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final int mSystemPid;
+
// List of currently registered key gesture event listeners keyed by process pid
@GuardedBy("mKeyGestureEventListenerRecords")
private final SparseArray<KeyGestureEventListenerRecord>
mKeyGestureEventListenerRecords = new SparseArray<>();
- public void onKeyGestureEvent(KeyGestureEvent event) {
+ // List of currently registered key gesture event handler keyed by process pid. The map sorts
+ // in the order of preference of the handlers, and we prioritize handlers in system server
+ // over external handlers..
+ @GuardedBy("mKeyGestureHandlerRecords")
+ private final TreeMap<Integer, KeyGestureHandlerRecord> mKeyGestureHandlerRecords;
+
+ KeyGestureController(Context context, Looper looper) {
+ mContext = context;
+ mHandler = new Handler(looper, this::handleMessage);
+ mSystemPid = Process.myPid();
+ mKeyGestureHandlerRecords = new TreeMap<>((p1, p2) -> {
+ if (Objects.equals(p1, p2)) {
+ return 0;
+ }
+ if (p1 == mSystemPid) {
+ return -1;
+ } else if (p2 == mSystemPid) {
+ return 1;
+ } else {
+ return Integer.compare(p1, p2);
+ }
+ });
+ }
+
+ public int interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+ // TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate
+ // KeyGestureHandler (PWM is one of the handlers)
+ return 0;
+ }
+
+ @VisibleForTesting
+ boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
+ @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId,
+ IBinder focusedToken, int flags) {
+ AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes,
+ modifierState, gestureType, action, displayId, flags);
+ synchronized (mKeyGestureHandlerRecords) {
+ for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
+ if (handler.handleKeyGesture(event, focusedToken)) {
+ Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT, event);
+ mHandler.sendMessage(msg);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
+ synchronized (mKeyGestureHandlerRecords) {
+ for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
+ if (handler.isKeyGestureSupported(gestureType)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
+ @KeyGestureEvent.KeyGestureType int gestureType) {
+ // TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally
+ // should not rely on PWM to tell us about the gesture start and end.
+ AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
+ gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, 0);
+ mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget();
+ }
+
+ @MainThread
+ private void notifyKeyGestureEvent(AidlKeyGestureEvent event) {
+ InputDevice device = getInputDevice(event.deviceId);
+ if (device == null || device.isVirtual()) {
+ return;
+ }
+ if (event.action == KeyGestureEvent.ACTION_GESTURE_COMPLETE) {
+ KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event.keycodes,
+ event.modifierState,
+ KeyGestureEvent.keyGestureTypeToLogEvent(event.gestureType));
+ }
+ notifyAllListeners(event);
+ }
+
+ @MainThread
+ private void notifyAllListeners(AidlKeyGestureEvent event) {
if (DEBUG) {
Slog.d(TAG, "Key gesture event occurred, event = " + event);
}
@@ -56,17 +162,26 @@
}
}
+ @MainThread
+ private boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_NOTIFY_KEY_GESTURE_EVENT:
+ AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj;
+ notifyKeyGestureEvent(event);
+ break;
+ }
+ return true;
+ }
+
/** Register the key gesture event listener for a process. */
@BinderThread
- public void registerKeyGestureEventListener(IKeyGestureEventListener listener,
- int pid) {
+ public void registerKeyGestureEventListener(IKeyGestureEventListener listener, int pid) {
synchronized (mKeyGestureEventListenerRecords) {
if (mKeyGestureEventListenerRecords.get(pid) != null) {
throw new IllegalStateException("The calling process has already registered "
+ "a KeyGestureEventListener.");
}
- KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord(
- pid, listener);
+ KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord(pid, listener);
try {
listener.asBinder().linkToDeath(record, 0);
} catch (RemoteException ex) {
@@ -78,8 +193,7 @@
/** Unregister the key gesture event listener for a process. */
@BinderThread
- public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener,
- int pid) {
+ public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener, int pid) {
synchronized (mKeyGestureEventListenerRecords) {
KeyGestureEventListenerRecord record =
mKeyGestureEventListenerRecords.get(pid);
@@ -120,10 +234,9 @@
onKeyGestureEventListenerDied(mPid);
}
- public void onKeyGestureEvent(KeyGestureEvent event) {
+ public void onKeyGestureEvent(AidlKeyGestureEvent event) {
try {
- mListener.onKeyGestureEvent(event.getDeviceId(), event.getKeycodes(),
- event.getModifierState(), event.getKeyGestureType());
+ mListener.onKeyGestureEvent(event);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify process " + mPid
+ " that key gesture event occurred, assuming it died.", ex);
@@ -131,4 +244,107 @@
}
}
}
+
+ /** Register the key gesture event handler for a process. */
+ @BinderThread
+ public void registerKeyGestureHandler(IKeyGestureHandler handler, int pid) {
+ synchronized (mKeyGestureHandlerRecords) {
+ if (mKeyGestureHandlerRecords.get(pid) != null) {
+ throw new IllegalStateException("The calling process has already registered "
+ + "a KeyGestureHandler.");
+ }
+ KeyGestureHandlerRecord record = new KeyGestureHandlerRecord(pid, handler);
+ try {
+ handler.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+ mKeyGestureHandlerRecords.put(pid, record);
+ }
+ }
+
+ /** Unregister the key gesture event handler for a process. */
+ @BinderThread
+ public void unregisterKeyGestureHandler(IKeyGestureHandler handler, int pid) {
+ synchronized (mKeyGestureHandlerRecords) {
+ KeyGestureHandlerRecord record = mKeyGestureHandlerRecords.get(pid);
+ if (record == null) {
+ throw new IllegalStateException("The calling process has no registered "
+ + "KeyGestureHandler.");
+ }
+ if (record.mKeyGestureHandler.asBinder() != handler.asBinder()) {
+ throw new IllegalStateException("The calling process has a different registered "
+ + "KeyGestureHandler.");
+ }
+ record.mKeyGestureHandler.asBinder().unlinkToDeath(record, 0);
+ mKeyGestureHandlerRecords.remove(pid);
+ }
+ }
+
+ private void onKeyGestureHandlerDied(int pid) {
+ synchronized (mKeyGestureHandlerRecords) {
+ mKeyGestureHandlerRecords.remove(pid);
+ }
+ }
+
+ // A record of a registered key gesture event listener from one process.
+ private class KeyGestureHandlerRecord implements IBinder.DeathRecipient {
+ public final int mPid;
+ public final IKeyGestureHandler mKeyGestureHandler;
+
+ KeyGestureHandlerRecord(int pid, IKeyGestureHandler keyGestureHandler) {
+ mPid = pid;
+ mKeyGestureHandler = keyGestureHandler;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.d(TAG, "Key gesture event handler for pid " + mPid + " died.");
+ }
+ onKeyGestureHandlerDied(mPid);
+ }
+
+ public boolean handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken) {
+ try {
+ return mKeyGestureHandler.handleKeyGesture(event, focusedToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to send key gesture to process " + mPid
+ + ", assuming it died.", ex);
+ binderDied();
+ }
+ return false;
+ }
+
+ public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
+ try {
+ return mKeyGestureHandler.isKeyGestureSupported(gestureType);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to identify if key gesture type is supported by the "
+ + "process " + mPid + ", assuming it died.", ex);
+ binderDied();
+ }
+ return false;
+ }
+ }
+
+ @Nullable
+ private InputDevice getInputDevice(int deviceId) {
+ InputManager inputManager = mContext.getSystemService(InputManager.class);
+ return inputManager != null ? inputManager.getInputDevice(deviceId) : null;
+ }
+
+ private AidlKeyGestureEvent createKeyGestureEvent(int deviceId, int[] keycodes,
+ int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action,
+ int displayId, int flags) {
+ AidlKeyGestureEvent event = new AidlKeyGestureEvent();
+ event.deviceId = deviceId;
+ event.keycodes = keycodes;
+ event.modifierState = modifierState;
+ event.gestureType = gestureType;
+ event.action = action;
+ event.displayId = displayId;
+ event.flags = flags;
+ return event;
+ }
}
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
index 1daf4db..609164a4 100644
--- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -24,7 +24,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.input.KeyGestureEvent;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria;
import android.icu.util.ULocale;
@@ -41,6 +40,7 @@
import com.android.internal.util.FrameworkStatsLog;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -60,23 +60,26 @@
@VisibleForTesting
public static final String DEFAULT_LANGUAGE_TAG = "None";
+ private static final int INVALID_SYSTEMS_EVENT = FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
+
/**
* Log keyboard system shortcuts for the proto
* {@link com.android.os.input.KeyboardSystemsEventReported}
* defined in "stats/atoms/input/input_extension_atoms.proto"
*/
public static void logKeyboardSystemsEventReportedAtom(@NonNull InputDevice inputDevice,
- @NonNull KeyGestureEvent keyGestureEvent) {
- if (inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
+ int[] keycodes, int modifierState, int systemsEvent) {
+ if (systemsEvent == INVALID_SYSTEMS_EVENT || inputDevice.isVirtual()
+ || !inputDevice.isFullKeyboard()) {
return;
}
FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
inputDevice.getVendorId(), inputDevice.getProductId(),
- keyGestureEvent.getKeyGestureType(), keyGestureEvent.getKeycodes(),
- keyGestureEvent.getModifierState(), inputDevice.getDeviceBus());
+ systemsEvent, keycodes, modifierState, inputDevice.getDeviceBus());
if (DEBUG) {
- Slog.d(TAG, "Logging Keyboard system event: " + keyGestureEvent);
+ Slog.d(TAG, "Logging Keyboard system event: " + modifierState + " + " + Arrays.toString(
+ keycodes) + " -> " + systemsEvent);
}
}
diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
index 486d4af..cc13e8e 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
@@ -16,6 +16,8 @@
package com.android.server.input.debug;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Configuration;
@@ -24,6 +26,7 @@
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.util.Slog;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -38,6 +41,13 @@
import java.util.Objects;
public class TouchpadDebugView extends LinearLayout {
+ private static final float MAX_SCREEN_WIDTH_PROPORTION = 0.4f;
+ private static final float MAX_SCREEN_HEIGHT_PROPORTION = 0.4f;
+ private static final float MIN_SCALE_FACTOR = 10f;
+ private static final float TEXT_SIZE_SP = 16.0f;
+ private static final float DEFAULT_RES_X = 47f;
+ private static final float DEFAULT_RES_Y = 45f;
+
/**
* Input device ID for the touchpad that this debug view is displaying.
*/
@@ -62,6 +72,7 @@
new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
new TouchpadFingerState[0]);
private TouchpadVisualizationView mTouchpadVisualizationView;
+ private final TouchpadHardwareProperties mTouchpadHardwareProperties;
public TouchpadDebugView(Context context, int touchpadId,
TouchpadHardwareProperties touchpadHardwareProperties) {
@@ -69,10 +80,10 @@
mTouchpadId = touchpadId;
mWindowManager =
Objects.requireNonNull(getContext().getSystemService(WindowManager.class));
- init(context, touchpadHardwareProperties, touchpadId);
+ mTouchpadHardwareProperties = touchpadHardwareProperties;
+ init(context, touchpadId);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- // TODO(b/360137366): Use the hardware properties to initialise layout parameters.
mWindowLayoutParams = new WindowManager.LayoutParams();
mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -92,8 +103,8 @@
mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
}
- private void init(Context context, TouchpadHardwareProperties touchpadHardwareProperties,
- int touchpadId) {
+ private void init(Context context, int touchpadId) {
+ updateScreenDimensions();
setOrientation(VERTICAL);
setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT,
@@ -102,35 +113,34 @@
TextView nameView = new TextView(context);
nameView.setBackgroundColor(Color.RED);
- nameView.setTextSize(20);
+ nameView.setTextSize(TEXT_SIZE_SP);
nameView.setText(Objects.requireNonNull(Objects.requireNonNull(
mContext.getSystemService(InputManager.class))
.getInputDevice(touchpadId)).getName());
nameView.setGravity(Gravity.CENTER);
nameView.setTextColor(Color.WHITE);
- nameView.setLayoutParams(new LayoutParams(1000, 200));
+ nameView.setLayoutParams(
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
mTouchpadVisualizationView = new TouchpadVisualizationView(context,
- touchpadHardwareProperties);
+ mTouchpadHardwareProperties);
mTouchpadVisualizationView.setBackgroundColor(Color.WHITE);
- //TODO(b/365568238): set the view size according to the touchpad size from the
- // TouchpadHardwareProperties
- mTouchpadVisualizationView.setLayoutParams(new LayoutParams(778, 500));
//TODO(b/365562952): Add a display for recognized gesture info here
TextView gestureInfoView = new TextView(context);
gestureInfoView.setBackgroundColor(Color.GRAY);
- gestureInfoView.setTextSize(20);
+ gestureInfoView.setTextSize(TEXT_SIZE_SP);
gestureInfoView.setText("Touchpad Debug View 3");
gestureInfoView.setGravity(Gravity.CENTER);
gestureInfoView.setTextColor(Color.BLACK);
- gestureInfoView.setLayoutParams(new LayoutParams(1000, 200));
+ gestureInfoView.setLayoutParams(
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
addView(nameView);
addView(mTouchpadVisualizationView);
addView(gestureInfoView);
- updateScreenDimensions();
+ updateViewsDimensions();
}
@Override
@@ -191,6 +201,7 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateScreenDimensions();
+ updateViewsDimensions();
// Adjust view position to stay within screen bounds after rotation
mWindowLayoutParams.x =
@@ -204,6 +215,41 @@
return deltaX * deltaX + deltaY * deltaY >= mTouchSlop * mTouchSlop;
}
+ private void updateViewsDimensions() {
+ float resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X
+ : mTouchpadHardwareProperties.getResX();
+ float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y
+ : mTouchpadHardwareProperties.getResY();
+
+ float touchpadHeightMm = Math.abs(
+ mTouchpadHardwareProperties.getBottom() - mTouchpadHardwareProperties.getTop())
+ / resY;
+ float touchpadWidthMm = Math.abs(
+ mTouchpadHardwareProperties.getLeft() - mTouchpadHardwareProperties.getRight())
+ / resX;
+
+ float maxViewWidthPx = mScreenWidth * MAX_SCREEN_WIDTH_PROPORTION;
+ float maxViewHeightPx = mScreenHeight * MAX_SCREEN_HEIGHT_PROPORTION;
+
+ float minScaleFactorPx = TypedValue.applyDimension(COMPLEX_UNIT_DIP, MIN_SCALE_FACTOR,
+ getResources().getDisplayMetrics());
+
+ float scaleFactorBasedOnWidth =
+ touchpadWidthMm * minScaleFactorPx > maxViewWidthPx ? maxViewWidthPx
+ / touchpadWidthMm : minScaleFactorPx;
+ float scaleFactorBasedOnHeight =
+ touchpadHeightMm * minScaleFactorPx > maxViewHeightPx ? maxViewHeightPx
+ / touchpadHeightMm : minScaleFactorPx;
+ float scaleFactorUsed = Math.min(scaleFactorBasedOnHeight, scaleFactorBasedOnWidth);
+
+ mTouchpadVisualizationView.setLayoutParams(
+ new LayoutParams((int) (touchpadWidthMm * scaleFactorUsed),
+ (int) (touchpadHeightMm * scaleFactorUsed)));
+
+ mTouchpadVisualizationView.updateScaleFactor(scaleFactorUsed);
+ mTouchpadVisualizationView.invalidate();
+ }
+
private void updateScreenDimensions() {
Rect windowBounds =
mWindowManager.getCurrentWindowMetrics().getBounds();
diff --git a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
index 9ba7d0a..67c3621 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
@@ -30,40 +30,52 @@
public class TouchpadVisualizationView extends View {
private static final String TAG = "TouchpadVizMain";
private static final boolean DEBUG = true;
+ private static final float DEFAULT_RES_X = 47f;
+ private static final float DEFAULT_RES_Y = 45f;
private final TouchpadHardwareProperties mTouchpadHardwareProperties;
+ private float mScaleFactor;
TouchpadHardwareState mLatestHardwareState = new TouchpadHardwareState(0, 0, 0, 0,
new TouchpadFingerState[]{});
- private final Paint mOvalPaint;
+ private final Paint mOvalStrokePaint;
+ private final Paint mOvalFillPaint;
+ private final RectF mTempOvalRect = new RectF();
public TouchpadVisualizationView(Context context,
TouchpadHardwareProperties touchpadHardwareProperties) {
super(context);
mTouchpadHardwareProperties = touchpadHardwareProperties;
- mOvalPaint = new Paint();
- mOvalPaint.setAntiAlias(true);
- mOvalPaint.setARGB(255, 0, 0, 0);
- mOvalPaint.setStyle(Paint.Style.STROKE);
+ mScaleFactor = 1;
+ mOvalStrokePaint = new Paint();
+ mOvalStrokePaint.setAntiAlias(true);
+ mOvalStrokePaint.setARGB(255, 0, 0, 0);
+ mOvalStrokePaint.setStyle(Paint.Style.STROKE);
+ mOvalFillPaint = new Paint();
+ mOvalFillPaint.setAntiAlias(true);
+ mOvalFillPaint.setARGB(255, 0, 0, 0);
}
- private final RectF mOvalRect = new RectF();
-
- private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle,
- Paint paint) {
+ private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(angle, x, y);
- mOvalRect.left = x - minor / 2;
- mOvalRect.right = x + minor / 2;
- mOvalRect.top = y - major / 2;
- mOvalRect.bottom = y + major / 2;
- canvas.drawOval(mOvalRect, paint);
+ mTempOvalRect.left = x - minor / 2;
+ mTempOvalRect.right = x + minor / 2;
+ mTempOvalRect.top = y - major / 2;
+ mTempOvalRect.bottom = y + major / 2;
+ canvas.drawOval(mTempOvalRect, mOvalStrokePaint);
+ canvas.drawOval(mTempOvalRect, mOvalFillPaint);
canvas.restore();
}
@Override
protected void onDraw(Canvas canvas) {
+ float maximumPressure = 0;
+ for (TouchpadFingerState touchpadFingerState : mLatestHardwareState.getFingerStates()) {
+ maximumPressure = Math.max(maximumPressure, touchpadFingerState.getPressure());
+ }
+
for (TouchpadFingerState touchpadFingerState : mLatestHardwareState.getFingerStates()) {
float newX = translateRange(mTouchpadHardwareProperties.getLeft(),
mTouchpadHardwareProperties.getRight(), 0, getWidth(),
@@ -73,16 +85,22 @@
mTouchpadHardwareProperties.getBottom(), 0, getHeight(),
touchpadFingerState.getPositionY());
- float newAngle = -translateRange(mTouchpadHardwareProperties.getOrientationMinimum(),
- mTouchpadHardwareProperties.getOrientationMaximum(), 0, 360,
- touchpadFingerState.getOrientation());
+ float newAngle = translateRange(0, mTouchpadHardwareProperties.getOrientationMaximum(),
+ 0, 90, touchpadFingerState.getOrientation());
- float newTouchMajor =
- touchpadFingerState.getTouchMajor() / mTouchpadHardwareProperties.getResX();
- float newTouchMinor =
- touchpadFingerState.getTouchMinor() / mTouchpadHardwareProperties.getResY();
+ float resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X
+ : mTouchpadHardwareProperties.getResX();
+ float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y
+ : mTouchpadHardwareProperties.getResY();
- drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle, mOvalPaint);
+ float newTouchMajor = touchpadFingerState.getTouchMajor() * mScaleFactor / resY;
+ float newTouchMinor = touchpadFingerState.getTouchMinor() * mScaleFactor / resX;
+
+ float pressureToOpacity = translateRange(0, maximumPressure, 0, 255,
+ touchpadFingerState.getPressure());
+ mOvalFillPaint.setAlpha((int) pressureToOpacity);
+
+ drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle);
}
}
@@ -101,6 +119,15 @@
invalidate();
}
+ /**
+ * Update the scale factor of the drawings in the view.
+ *
+ * @param scaleFactor the new scale factor
+ */
+ public void updateScaleFactor(float scaleFactor) {
+ mScaleFactor = scaleFactor;
+ }
+
private float translateRange(float rangeBeforeMin, float rangeBeforeMax,
float rangeAfterMin, float rangeAfterMax, float value) {
return rangeAfterMin + (value - rangeBeforeMin) / (rangeBeforeMax - rangeBeforeMin) * (
diff --git a/services/core/java/com/android/server/locksettings/Android.bp b/services/core/java/com/android/server/locksettings/Android.bp
new file mode 100644
index 0000000..53f1ac6
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/Android.bp
@@ -0,0 +1,11 @@
+aconfig_declarations {
+ name: "locksettings_flags",
+ package: "com.android.server.locksettings",
+ container: "system",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "locksettings_flags_lib",
+ aconfig_declarations: "locksettings_flags",
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7d44ba1..3780fbd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -16,7 +16,6 @@
package com.android.server.locksettings;
-import static android.security.Flags.reportPrimaryAuthAttempts;
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.Manifest.permission.CONFIGURE_FACTORY_RESET_PROTECTION;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
@@ -32,6 +31,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;
+import static android.security.Flags.reportPrimaryAuthAttempts;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
@@ -1836,6 +1836,13 @@
}
/**
+ * Set a new LSKF for the given user/profile. Only succeeds if the synthetic password for the
+ * user is protected by the given {@param savedCredential}.
+ * <p>
+ * When {@link android.security.Flags#clearStrongAuthOnAddPrimaryCredential()} is enabled and
+ * setting a new credential where there was none, updates the strong auth state for
+ * {@param userId} to <tt>STRONG_AUTH_NOT_REQUIRED</tt>.
+ *
* @param savedCredential if the user is a profile with
* {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
* savedCredential is empty, LSS will try to re-derive the profile password internally.
@@ -1884,6 +1891,12 @@
onSyntheticPasswordUnlocked(userId, sp);
setLockCredentialWithSpLocked(credential, sp, userId);
+ if (android.security.Flags.clearStrongAuthOnAddPrimaryCredential()
+ && savedCredential.isNone() && !credential.isNone()) {
+ // Clear the strong auth value, since the LSKF has just been entered and set,
+ // but only when the previous credential was None.
+ mStrongAuth.reportUnlock(userId);
+ }
sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
return true;
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index f44b852..820c0ef 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -273,11 +273,6 @@
"server_based_ror_enabled", false);
}
- public boolean waitForInternet() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_OTA, "wait_for_internet_ror", false);
- }
-
public boolean isNetworkConnected() {
final ConnectivityManager connectivityManager =
mContext.getSystemService(ConnectivityManager.class);
@@ -433,7 +428,7 @@
/** Wrapper function to set error code serialized through handler, */
private void setLoadEscrowDataErrorCode(@RebootEscrowErrorCode int value, Handler handler) {
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
mInjector.post(
handler,
() -> {
@@ -516,7 +511,7 @@
mWakeLock.acquire(mInjector.getWakeLockTimeoutMillis());
}
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
// Timeout to stop retrying same as the wake lock timeout.
mInjector.postDelayed(
retryHandler,
@@ -553,7 +548,7 @@
return;
}
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
if (mRebootEscrowTimedOut) {
Slog.w(TAG, "Failed to load reboot escrow data within timeout");
compareAndSetLoadEscrowDataErrorCode(
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index cc58f38..3a429b0 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -1701,7 +1701,7 @@
.setGatekeeperHAT(response.getPayload()).build();
if (response.getShouldReEnroll()) {
try {
- response = gatekeeper.enroll(userId, spHandle, spHandle,
+ response = gatekeeper.enroll(userId, spHandle, gatekeeperPassword,
gatekeeperPassword);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to invoke gatekeeper.enroll", e);
diff --git a/services/core/java/com/android/server/locksettings/flags.aconfig b/services/core/java/com/android/server/locksettings/flags.aconfig
new file mode 100644
index 0000000..6818de9
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.locksettings"
+container: "system"
+
+flag {
+ name: "wait_for_internet_ror"
+ namespace: "sudo"
+ description: "Feature flag to wait for internet connectivity before calling resume on reboot server."
+ bug: "231660348"
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 4fa7112..82e00d9 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -757,8 +757,12 @@
// scenario 3: sparse/singleton groups
if (Flags.notificationForceGroupSingletons()) {
- groupSparseGroups(record, notificationList, summaryByGroupKey, sectioner,
- fullAggregateGroupKey);
+ try {
+ groupSparseGroups(record, notificationList, summaryByGroupKey, sectioner,
+ fullAggregateGroupKey);
+ } catch (Throwable e) {
+ Slog.wtf(TAG, "Failed to group sparse groups", e);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e2ec006..ba7d4d2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -51,6 +51,7 @@
import static android.app.NotificationChannel.PROMOTIONS_ID;
import static android.app.NotificationChannel.RECS_ID;
import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
+import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED;
@@ -109,6 +110,7 @@
import static android.service.notification.Adjustment.TYPE_PROMOTION;
import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
import static android.service.notification.Flags.callstyleCallbackApi;
+import static android.service.notification.Flags.notificationClassification;
import static android.service.notification.Flags.notificationForceGrouping;
import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle;
import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners;
@@ -4405,6 +4407,15 @@
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
throw new IllegalArgumentException("Cannot delete default channel");
}
+ if (notificationClassification()) {
+ // Check for all reserved channels, but do not throw because it's a common
+ // preexisting pattern for apps to (try to) delete all channels that don't match
+ // their current desired channel structure
+ if (SYSTEM_RESERVED_IDS.contains(channelId)) {
+ Log.v(TAG, "Package " + pkg + " cannot delete a reserved channel");
+ return;
+ }
+ }
enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId);
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 821722b..a4fdb75 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,6 +22,7 @@
import static android.app.NotificationChannel.PROMOTIONS_ID;
import static android.app.NotificationChannel.RECS_ID;
import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
+import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
@@ -440,6 +441,12 @@
channel.setImportanceLockedByCriticalDeviceFunction(
r.defaultAppLockedImportance || r.fixedImportance);
+ if (notificationClassification()) {
+ if (SYSTEM_RESERVED_IDS.contains(id) && channel.isDeleted() ) {
+ channel.setDeleted(false);
+ }
+ }
+
if (isShortcutOk(channel) && isDeletionOk(channel)) {
r.channels.put(id, channel);
}
@@ -1023,6 +1030,11 @@
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
throw new IllegalArgumentException("Reserved id");
}
+ // Only the user can update bundle channel settings
+ if (notificationClassification() && !fromSystemOrSystemUi
+ && SYSTEM_RESERVED_IDS.contains(channel.getId())) {
+ return false;
+ }
NotificationChannel existing = r.channels.get(channel.getId());
if (existing != null && fromTargetApp) {
// Actually modifying an existing channel - keep most of the existing settings
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
index b03a54e..fcc5e97 100644
--- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java
+++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
@@ -419,7 +419,7 @@
if (config.automaticRules != null) {
for (ZenModeConfig.ZenRule rule : config.automaticRules.values()) {
- if (rule != null && rule.isAutomaticActive()) {
+ if (rule != null && rule.isActive()) {
rules.add(rule);
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 2ada9ae4..e9db1b5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -887,7 +887,7 @@
return Condition.STATE_UNKNOWN;
}
if (Flags.modesApi() && Flags.modesUi()) {
- return rule.isAutomaticActive() ? STATE_TRUE : STATE_FALSE;
+ return rule.isActive() ? STATE_TRUE : STATE_FALSE;
} else {
// Buggy, does not consider snoozing!
return rule.condition != null ? rule.condition.state : STATE_FALSE;
@@ -967,12 +967,12 @@
// snoozing-unsnoozing or activating-stopping.
if (condition.state == STATE_TRUE) {
rule.resetConditionOverride();
- if (!rule.isAutomaticActive()) {
+ if (!rule.isActive()) {
rule.setConditionOverride(OVERRIDE_ACTIVATE);
}
} else if (condition.state == STATE_FALSE) {
rule.resetConditionOverride();
- if (rule.isAutomaticActive()) {
+ if (rule.isActive()) {
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
}
}
@@ -1609,7 +1609,7 @@
// User deactivation of DND means just turning off the manual DND rule.
// For API calls (different origin) keep old behavior of snoozing all rules.
for (ZenRule automaticRule : newConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
automaticRule.setConditionOverride(OVERRIDE_DEACTIVATE);
}
}
@@ -1618,7 +1618,7 @@
if (zenMode == Global.ZEN_MODE_OFF) {
newConfig.manualRule = null;
for (ZenRule automaticRule : newConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
automaticRule.setConditionOverride(OVERRIDE_DEACTIVATE);
}
}
@@ -1665,7 +1665,7 @@
mConfig.manualRule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
}
for (ZenRule rule : mConfig.automaticRules.values()) {
- if (rule.isAutomaticActive()) {
+ if (rule.isActive()) {
rule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
}
}
@@ -2020,9 +2020,9 @@
scheduleEnabledBroadcast(
rule.getPkg(), config.user, rule.id, rule.enabled);
}
- if (original.isAutomaticActive() != rule.isAutomaticActive()) {
+ if (original.isActive() != rule.isActive()) {
scheduleActivationBroadcast(
- rule.getPkg(), config.user, rule.id, rule.isAutomaticActive());
+ rule.getPkg(), config.user, rule.id, rule.isActive());
}
}
}
@@ -2106,7 +2106,7 @@
if (mConfig.isManualActive()) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
// automatic rule triggered dnd and user hasn't seen update dnd dialog
if (Settings.Secure.getInt(mContext.getContentResolver(),
@@ -2182,7 +2182,7 @@
}
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
// Active rules with INTERRUPTION_FILTER_ALL are not included in consolidated
// policy. This is relevant in case some other active rule has a more
// restrictive INTERRUPTION_FILTER but a more lenient ZenPolicy!
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index 9ef2e12..f6d9dc2 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -648,6 +648,21 @@
Slog.w(TAG, "Failed to send connected event", ex);
}
}
+
+ @Override
+ public void onDisconnected(
+ @NonNull IOnDeviceSandboxedInferenceService service) {
+ ensureRemoteIntelligenceServiceInitialized();
+ mRemoteOnDeviceIntelligenceService.run(
+ IOnDeviceIntelligenceService::notifyInferenceServiceDisconnected);
+ }
+
+ @Override
+ public void onBinderDied() {
+ ensureRemoteIntelligenceServiceInitialized();
+ mRemoteOnDeviceIntelligenceService.run(
+ IOnDeviceIntelligenceService::notifyInferenceServiceDisconnected);
+ }
});
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 023f765..ee15bec 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -92,6 +92,7 @@
import android.multiuser.Flags;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IInterface;
@@ -214,7 +215,7 @@
@VisibleForTesting
static class LauncherAppsImpl extends ILauncherApps.Stub {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Build.IS_DEBUGGABLE;
private static final String TAG = "LauncherAppsService";
private static final String NAMESPACE_MULTIUSER = "multiuser";
private static final String FLAG_NON_SYSTEM_ACCESS_TO_HIDDEN_PROFILES =
@@ -495,8 +496,28 @@
private boolean canAccessProfile(int callingUid, int callingUserId, int callingPid,
int targetUserId, String message) {
- if (targetUserId == callingUserId) return true;
+ if (DEBUG) {
+ final AndroidPackage callingPackage =
+ mPackageManagerInternal.getPackage(callingUid);
+ final String callingPackageName = callingPackage == null
+ ? null : callingPackage.getPackageName();
+ Slog.v(TAG, "canAccessProfile called by " + callingPackageName
+ + " for user " + callingUserId
+ + " requesting to access user "
+ + targetUserId + " when invoking " + message);
+ }
+ if (targetUserId == callingUserId) {
+ if (DEBUG) {
+ Slog.v(TAG, message + " passed canAccessProfile for targetuser"
+ + targetUserId + " because it is the same as the calling user");
+ }
+ return true;
+ }
if (injectHasInteractAcrossUsersFullPermission(callingPid, callingUid)) {
+ if (DEBUG) {
+ Slog.v(TAG, message + " passed because calling process"
+ + "has permission to interact across users");
+ }
return true;
}
@@ -514,11 +535,25 @@
if (isHiddenProfile(UserHandle.of(targetUserId))
&& !canAccessHiddenProfile(callingUid, callingPid)) {
+ Slog.w(TAG, message + " for hidden profile user " + targetUserId
+ + " from " + callingUserId + " not allowed");
+
return false;
}
- return mUserManagerInternal.isProfileAccessible(callingUserId, targetUserId,
- message, true);
+ final boolean ret = mUserManagerInternal.isProfileAccessible(
+ callingUserId, targetUserId, message, true);
+ if (DEBUG) {
+ final AndroidPackage callingPackage =
+ mPackageManagerInternal.getPackage(callingUid);
+ final String callingPackageName = callingPackage == null
+ ? null : callingPackage.getPackageName();
+ Slog.v(TAG, "canAccessProfile returned " + ret + " for " + callingPackageName
+ + " for user " + callingUserId
+ + " requesting to access user "
+ + targetUserId + " when invoking " + message);
+ }
+ return ret;
}
private boolean isHiddenProfile(UserHandle targetUser) {
@@ -1341,6 +1376,10 @@
@Override
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
UserHandle targetUser) {
+ if (DEBUG) {
+ Slog.v(TAG, "pinShortcuts: " + callingPackage + " is pinning shortcuts from "
+ + packageName + " for user " + targetUser);
+ }
if (!mShortcutServiceInternal
.areShortcutsSupportedOnHomeScreen(targetUser.getIdentifier())) {
// Requires strict ACCESS_SHORTCUTS permission for user-profiles with items
@@ -1351,6 +1390,11 @@
}
ensureShortcutPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) {
+ if (DEBUG) {
+ Slog.v(TAG, "pinShortcuts: " + callingPackage
+ + " is pinning shortcuts from " + packageName
+ + " for user " + targetUser + " but cannot access profile");
+ }
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index be6fa14..1316df1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -856,8 +856,9 @@
params.appPackageName, SYSTEM_UID);
if (ps != null
&& PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))
- && PackageArchiver.getResponsibleInstallerPackage(ps)
- .equals(requestedInstallerPackageName)) {
+ && TextUtils.equals(
+ PackageArchiver.getResponsibleInstallerPackage(ps),
+ requestedInstallerPackageName)) {
params.installFlags |= PackageManager.INSTALL_UNARCHIVE;
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 045d4db..d65e30b 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -42,6 +42,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Launcher information used by {@link ShortcutService}.
@@ -128,9 +129,15 @@
*/
public void pinShortcuts(@UserIdInt int packageUserId,
@NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) {
+ if (ShortcutService.DEBUG) {
+ Slog.v(TAG, "ShortcutLauncher#pinShortcuts: pin shortcuts from " + packageName
+ + " with userId=" + packageUserId + " shortcutIds="
+ + ids.stream().collect(Collectors.joining(", ", "[", "]")));
+ }
final ShortcutPackage packageShortcuts =
mShortcutUser.getPackageShortcutsIfExists(packageName);
if (packageShortcuts == null) {
+ Slog.w(TAG, "ShortcutLauncher#pinShortcuts packageShortcuts is null");
return; // No need to instantiate.
}
@@ -155,6 +162,10 @@
final String id = ids.get(i);
final ShortcutInfo si = packageShortcuts.findShortcutById(id);
if (si == null) {
+ if (ShortcutService.DEBUG) {
+ Slog.w(TAG, "ShortcutLauncher#pinShortcuts: cannot pin "
+ + id + " because it does not exist");
+ }
continue;
}
if (si.isDynamic() || si.isLongLived()
@@ -174,6 +185,13 @@
}
}
}
+ if (ShortcutService.DEBUG) {
+ Slog.v(TAG, "ShortcutLauncher#pinShortcuts: "
+ + " newSet: " + newSet.stream().collect(
+ Collectors.joining(", ", "[", "]"))
+ + " floatingSet: " + floatingSet.stream().collect(
+ Collectors.joining(", ", "[", "]")));
+ }
mPinnedShortcuts.put(up, newSet);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 60056eb..c9ad498 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -729,6 +729,11 @@
}
pinnedShortcuts.addAll(pinned);
});
+ if (ShortcutService.DEBUG) {
+ Slog.v(TAG, "ShortcutPackage#refreshPinnedFlags: "
+ + " pinnedShortcuts: " + pinnedShortcuts.stream().collect(
+ Collectors.joining(", ", "[", "]")));
+ }
// Secondly, update the pinned state if necessary.
final List<ShortcutInfo> pinned = findAll(pinnedShortcuts);
if (pinned != null) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a3ff195..ea495c9 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -169,7 +169,7 @@
public class ShortcutService extends IShortcutService.Stub {
static final String TAG = "ShortcutService";
- static final boolean DEBUG = false; // STOPSHIP if true
+ static final boolean DEBUG = Build.IS_DEBUGGABLE; // STOPSHIP if true
static final boolean DEBUG_LOAD = false; // STOPSHIP if true
static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
static final boolean DEBUG_REBOOT = Build.IS_DEBUGGABLE;
@@ -3206,6 +3206,11 @@
public void pinShortcuts(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId) {
+ if (DEBUG) {
+ Slog.v(TAG, "pinShortcuts: " + callingPackage + ", with userId=" + launcherUserId
+ + ", is trying to pin shortcuts from " + packageName
+ + " with userId=" + userId);
+ }
// Calling permission must be checked by LauncherAppsImpl.
Preconditions.checkStringNotEmpty(packageName, "packageName");
Objects.requireNonNull(shortcutIds, "shortcutIds");
@@ -3230,6 +3235,11 @@
&& !si.isDeclaredInManifest(),
ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO,
callingPackage, launcherUserId, false);
+ } else {
+ if (DEBUG) {
+ Slog.w(TAG, "specified package " + packageName + ", with userId=" + userId
+ + ", doesn't exist.");
+ }
}
// Get list of shortcuts that will get unpinned.
ArraySet<String> oldPinnedIds = launcher.getPinnedShortcutIds(packageName, userId);
@@ -5448,6 +5458,17 @@
*/
private List<ShortcutInfo> prepareChangedShortcuts(ArraySet<String> changedIds,
ArraySet<String> newIds, List<ShortcutInfo> deletedList, final ShortcutPackage ps) {
+ if (DEBUG) {
+ Slog.v(TAG, "prepareChangedShortcuts: "
+ + " changedIds=" + (changedIds == null
+ ? "n/a" : changedIds.stream().collect(Collectors.joining(", ", "[", "]")))
+ + " newIds=" + (newIds == null
+ ? "n/a" : newIds.stream().collect(Collectors.joining(", ", "[", "]")))
+ + " deletedList=" + (deletedList == null
+ ? "n/a" : deletedList.stream().map(ShortcutInfo::getId).collect(
+ Collectors.joining(", ", "[", "]")))
+ + " ps=" + (ps == null ? "n/a" : ps.getPackageName()));
+ }
if (ps == null) {
// This can happen when package restore is not finished yet.
return null;
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index 4ce01d2..935a238 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -30,10 +30,7 @@
]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.power"}
- ]
+ "name": "FrameworksServicesTests_android_server_power"
},
{
"name": "PowerServiceTests",
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 6847a5c..dc6b164 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -1628,9 +1628,9 @@
long mInactivityThresholdMillis = INACTIVITY_THRESHOLD_MILLIS;
void updateThresholds() {
- synchronized (mSamples) {
- List<TemperatureThreshold> thresholds =
+ List<TemperatureThreshold> thresholds =
mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
+ synchronized (mSamples) {
if (Flags.allowThermalHeadroomThresholds()) {
Arrays.fill(mHeadroomThresholds, Float.NaN);
}
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index f6c3d8e..1346a29 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -160,6 +160,8 @@
private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
+ private Boolean mFMQUsesIntegratedEventFlag = false;
+
@VisibleForTesting final IHintManager.Stub mService = new BinderService();
public HintManagerService(Context context) {
@@ -1032,7 +1034,7 @@
@Override
public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
@NonNull int[] tids, long durationNanos, @SessionTag int tag,
- @Nullable SessionConfig config) {
+ SessionConfig config) {
if (!isHalSupported()) {
throw new UnsupportedOperationException("PowerHAL is not supported!");
}
@@ -1070,7 +1072,7 @@
default -> tag = SessionTag.APP;
}
}
-
+ config.id = -1;
Long halSessionPtr = null;
if (mConfigCreationSupport.get()) {
try {
@@ -1109,7 +1111,7 @@
}
}
- final long sessionId = config != null ? config.id : halSessionPtr;
+ final long sessionId = config.id != -1 ? config.id : halSessionPtr;
logPerformanceHintSessionAtom(
callingUid, sessionId, durationNanos, tids, tag);
@@ -1144,14 +1146,23 @@
}
@Override
- public ChannelConfig getSessionChannel(IBinder token) {
- if (mPowerHalVersion < 5 || !adpfUseFmqChannel()) {
+ public @Nullable ChannelConfig getSessionChannel(IBinder token) {
+ if (mPowerHalVersion < 5 || !adpfUseFmqChannel()
+ || mFMQUsesIntegratedEventFlag) {
return null;
}
java.util.Objects.requireNonNull(token);
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final int callingUid = Binder.getCallingUid();
ChannelItem item = getOrCreateMappedChannelItem(callingTgid, callingUid, token);
+ // FMQ V1 requires a separate event flag to be passed, and the default no-op
+ // implmenentation in PowerHAL does not return such a shared flag. This helps
+ // avoid using the FMQ on a default impl that does not support it.
+ if (item.getConfig().eventFlagDescriptor == null) {
+ mFMQUsesIntegratedEventFlag = true;
+ closeSessionChannel();
+ return null;
+ }
return item.getConfig();
};
@@ -1270,8 +1281,14 @@
@VisibleForTesting
boolean updateHintAllowedByProcState(boolean allowed) {
synchronized (this) {
- if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) resume();
- if (!allowed && mUpdateAllowedByProcState) pause();
+ if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) {
+ Slogf.e(TAG, "ADPF IS GETTING RESUMED? UID: " + mUid + " TAG: " + mTag);
+ resume();
+ }
+ if (!allowed && mUpdateAllowedByProcState) {
+ Slogf.e(TAG, "ADPF IS GETTING PAUSED? UID: " + mUid + " TAG: " + mTag);
+ pause();
+ }
mUpdateAllowedByProcState = allowed;
return mUpdateAllowedByProcState;
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 680b1ac..cb8e1a0 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -5031,9 +5031,7 @@
if (mPretendScreenOff != pretendScreenOff) {
mPretendScreenOff = pretendScreenOff;
final int primaryScreenState = mPerDisplayBatteryStats[0].screenState;
- noteScreenStateLocked(0, primaryScreenState,
- mClock.elapsedRealtime(), mClock.uptimeMillis(),
- mClock.currentTimeMillis());
+ noteScreenStateLocked(0, primaryScreenState);
}
}
@@ -5554,15 +5552,29 @@
}
}
+ private static String getScreenStateTag(
+ int display, int state, @Display.StateReason int reason) {
+ return String.format(
+ "display=%d state=%s reason=%s",
+ display, Display.stateToString(state), Display.stateReasonToString(reason));
+ }
+
@GuardedBy("this")
public void noteScreenStateLocked(int display, int state) {
- noteScreenStateLocked(display, state, mClock.elapsedRealtime(), mClock.uptimeMillis(),
- mClock.currentTimeMillis());
+ noteScreenStateLocked(display, state, Display.STATE_REASON_UNKNOWN,
+ mClock.elapsedRealtime(), mClock.uptimeMillis(), mClock.currentTimeMillis());
}
@GuardedBy("this")
public void noteScreenStateLocked(int display, int displayState,
- long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
+ @Display.StateReason int displayStateReason, long elapsedRealtimeMs, long uptimeMs,
+ long currentTimeMs) {
+ if (Flags.batteryStatsScreenStateEvent()) {
+ mHistory.recordEvent(
+ elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_DISPLAY_STATE_CHANGED,
+ getScreenStateTag(display, displayState, displayStateReason),
+ Process.INVALID_UID);
+ }
// Battery stats relies on there being 4 states. To accommodate this, new states beyond the
// original 4 are mapped to one of the originals.
if (displayState > MAX_TRACKED_SCREEN_STATE) {
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index cc0a283..05d29f5 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -68,3 +68,11 @@
description: "Disable deprecated BatteryUsageStatsAtom pulled atom"
bug: "324602949"
}
+
+flag {
+ name: "battery_stats_screen_state_event"
+ namespace: "backstage_power"
+ description: "Guards the battery stats event for screen state changes."
+ bug: "364350206"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 06a2565..8121701 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -51,6 +51,7 @@
import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_HARDWARE;
import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE;
import static android.os.UserHandle.USER_NULL;
+import static android.os.UserHandle.getCallingUserId;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION;
@@ -187,6 +188,7 @@
private final TelephonyManager mTelephonyManager;
private final PackageManagerInternal mPackageManagerInternal;
private final NotificationManager mNotificationManager;
+ private final UserManager mUserManager;
private CameraPrivacyLightController mCameraPrivacyLightController;
@@ -214,6 +216,7 @@
mTelephonyManager = context.getSystemService(TelephonyManager.class);
mPackageManagerInternal = getLocalService(PackageManagerInternal.class);
mNotificationManager = mContext.getSystemService(NotificationManager.class);
+ mUserManager = context.getSystemService(UserManager.class);
mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl();
for (String entry : SystemConfig.getInstance().getCameraPrivacyAllowlist()) {
mCameraPrivacyAllowlist.add(entry);
@@ -379,14 +382,23 @@
public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
Bundle prevRestrictions) {
// Reset sensor privacy when restriction is added
+ // Note: isValidCallingUser needs to be called before resetting sensor privacy
+ // because DISALLOW_CAMERA_TOGGLE and DISALLOW_MICROPHONE_TOGGLE are applied on
+ // visible background users in Automotive's Multi Display configuration but we don't
+ // allow sensor privacy to be set on a visible background user.
if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)
&& newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) {
- setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA, false);
+ if (isValidCallingUser(userId)) {
+ setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA,
+ false);
+ }
}
if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)
&& newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) {
- setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE,
- false);
+ if (isValidCallingUser(userId)) {
+ setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE,
+ false);
+ }
}
}
@@ -779,6 +791,10 @@
@Override
public void setSensorPrivacy(boolean enable) {
enforceManageSensorPrivacyPermission();
+
+ // Enforce valid calling user on devices that enable visible background users.
+ enforceValidCallingUser(getCallingUserId());
+
mSensorPrivacyStateController.setAllSensorState(enable);
}
@@ -795,11 +811,15 @@
+ " enable=" + enable
+ ")");
}
+
enforceManageSensorPrivacyPermission();
if (userId == UserHandle.USER_CURRENT) {
userId = mCurrentUser;
}
+ // Enforce valid calling user on devices that enable visible background users.
+ enforceValidCallingUser(userId);
+
if (!canChangeToggleSensorPrivacy(userId, sensor)) {
return;
}
@@ -831,6 +851,9 @@
userId = mCurrentUser;
}
+ // Enforce valid calling user on devices that enable visible background users.
+ enforceValidCallingUser(userId);
+
if (!canChangeToggleSensorPrivacy(userId, sensor)) {
return;
}
@@ -1151,6 +1174,42 @@
});
}
+ // This method enforces valid calling user on devices that enable visible background users.
+ // Only system user or current user or the user that belongs to the same profile group
+ // as the current user is permitted to toggle sensor privacy.
+ // Visible background users are not permitted to toggle sensor privacy.
+ private void enforceValidCallingUser(@UserIdInt int userId) {
+ if (!isValidCallingUser(userId)) {
+ throw new SecurityException("User " + userId
+ + " is not permitted to toggle sensor privacy");
+ }
+ }
+
+ private boolean isValidCallingUser(@UserIdInt int userId) {
+ // Check whether visible background users are enabled.
+ // Visible background users are non current but can have UI access.
+ // The main use case for visible background users is the passenger in Automotive's
+ // Multi-Display configuration.
+ if (!UserManager.isVisibleBackgroundUsersEnabled()) {
+ return true;
+ }
+
+ if (userId == UserHandle.USER_SYSTEM || userId == mCurrentUser) {
+ return true;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mUserManager.isSameProfileGroup(userId, mCurrentUser)) {
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ return false;
+ }
+
/**
* Enforces the caller contains the necessary permission to change the state of sensor
* privacy.
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
index 195e91c..49825f1 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
@@ -64,13 +64,36 @@
String targetPkg, int targetUserId);
/**
- * Same as {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int)}, but with an
- * extra parameter {@code requireContentUriPermissionFromCaller}, which is the value from {@link
- * android.R.attr#requireContentUriPermissionFromCaller} attribute.
+ * Same as {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int)}, but with:
+ * - {@code requireContentUriPermissionFromCaller}, which is the value from {@link
+ * android.R.attr#requireContentUriPermissionFromCaller} attribute.
+ * - {@code requestHashCode}, which is required to differentiate activity launches for logging
+ * ContentOrFileUriEventReported message.
*/
NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId,
- @RequiredContentUriPermission int requireContentUriPermissionFromCaller);
+ @RequiredContentUriPermission int requireContentUriPermissionFromCaller,
+ int requestHashCode);
+
+ /**
+ * Notify that an activity launch request has been completed and perform the following actions:
+ * - If the activity launch was unsuccessful, then clean up all the collected the content URIs
+ * that were passed during that launch.
+ * - If the activity launch was successful, then log cog content URIs that were passed during
+ * that launch. Specifically:
+ * - The caller didn't have read permission to them.
+ * - The activity's {@link android.R.attr#requireContentUriPermissionFromCaller} was set to
+ * "none".
+ *
+ * <p>Note that:
+ * - The API has to be called after
+ * {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int, int, int)} was called.
+ * - The API is not idempotent, i.e. content URIs may be logged only once because the API clears
+ * the content URIs after logging.
+ */
+ void notifyActivityLaunchRequestCompleted(int requestHashCode, boolean isSuccessfulLaunch,
+ String intentAction, int callingUid, String callingActivityName, int calleeUid,
+ String calleeActivityName, boolean isStartActivityForResult);
/**
* Extend a previously calculated set of permissions grants to the given
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index a581b08..3479b6c 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -24,6 +24,7 @@
import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_NONE;
+import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_READ;
import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_READ_OR_WRITE;
import static android.content.pm.ActivityInfo.isRequiredContentUriPermissionRead;
import static android.content.pm.ActivityInfo.isRequiredContentUriPermissionWrite;
@@ -39,6 +40,8 @@
import static android.os.Process.myUid;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.FrameworkStatsLog.CONTENT_OR_FILE_URI_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.CONTENT_OR_FILE_URI_EVENT_REPORTED__EVENT_TYPE__CONTENT_URI_WITHOUT_CALLER_READ_PERMISSION;
import static com.android.server.uri.UriGrantsManagerService.H.PERSIST_URI_GRANTS_MSG;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -78,6 +81,7 @@
import android.provider.Downloads;
import android.text.format.DateUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -86,6 +90,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -153,6 +158,22 @@
private final SparseArray<ArrayMap<GrantUri, UriPermission>>
mGrantedUriPermissions = new SparseArray<>();
+ /**
+ * Global map of activity launches to sets of passed content URIs. Specifically:
+ * - The caller didn't have read permission to them.
+ * - The callee activity's {@link android.R.attr#requireContentUriPermissionFromCaller} was set
+ * to "none".
+ *
+ * <p>This map is used for logging the ContentOrFileUriEventReported message.
+ *
+ * <p>The launch id is the ActivityStarter.Request#hashCode and has to be received from
+ * ActivityStarter to {@link #checkGrantUriPermissionFromIntentUnlocked(int, String, Intent,
+ * int, NeededUriGrants, int, Integer, Integer)}.
+ */
+ @GuardedBy("mLaunchToContentUrisWithoutCallerReadPermission")
+ private final SparseArray<ArraySet<Uri>> mLaunchToContentUrisWithoutCallerReadPermission =
+ new SparseArray<>();
+
private UriGrantsManagerService() {
this(SystemServiceManager.ensureSystemDir(), "uri-grants");
}
@@ -613,7 +634,8 @@
/** Like checkGrantUriPermission, but takes an Intent. */
private NeededUriGrants checkGrantUriPermissionFromIntentUnlocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId,
- @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ Integer requestHashCode) {
if (DEBUG) Slog.v(TAG,
"Checking URI perm to data=" + (intent != null ? intent.getData() : null)
+ " clip=" + (intent != null ? intent.getClipData() : null)
@@ -635,8 +657,9 @@
}
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(intent, contentUserHint,
- mode, callingUid, requireContentUriPermissionFromCaller);
+ enforceRequireContentUriPermissionFromCallerOnIntentExtraStreamUnlocked(intent,
+ contentUserHint, mode, callingUid, requireContentUriPermissionFromCaller,
+ requestHashCode);
}
Uri data = intent.getData();
@@ -660,8 +683,9 @@
if (data != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, data, mode);
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCaller(requireContentUriPermissionFromCaller,
- grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, mode,
targetUid);
@@ -678,8 +702,9 @@
if (uri != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg,
grantUri, mode, targetUid);
@@ -694,7 +719,7 @@
if (clipIntent != null) {
NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, clipIntent, mode, needed, targetUserId,
- requireContentUriPermissionFromCaller);
+ requireContentUriPermissionFromCaller, requestHashCode);
if (newNeeded != null) {
needed = newNeeded;
}
@@ -706,17 +731,32 @@
return needed;
}
- private void enforceRequireContentUriPermissionFromCaller(
+ private void enforceRequireContentUriPermissionFromCallerUnlocked(
@RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
- GrantUri grantUri, int uid) {
- // Ignore if requireContentUriPermissionFromCaller hasn't been set or the URI is a
+ GrantUri grantUri, int callingUid, Integer requestHashCode) {
+ // Exit early if requireContentUriPermissionFromCaller hasn't been set or the URI is a
// non-content URI.
if (requireContentUriPermissionFromCaller == null
|| requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_NONE
|| !ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
+ tryAddingContentUriWithoutCallerReadPermissionWhenAttributeIsNoneUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid, requestHashCode);
return;
}
+ final boolean hasPermission = hasRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid);
+
+ if (!hasPermission) {
+ throw new SecurityException("You can't launch this activity because you don't have the"
+ + " required " + ActivityInfo.requiredContentUriPermissionToShortString(
+ requireContentUriPermissionFromCaller) + " access to " + grantUri.uri);
+ }
+ }
+
+ private boolean hasRequireContentUriPermissionFromCallerUnlocked(
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ GrantUri grantUri, int uid) {
final boolean readMet = !isRequiredContentUriPermissionRead(
requireContentUriPermissionFromCaller)
|| checkContentUriPermissionFullUnlocked(grantUri, uid,
@@ -727,26 +767,48 @@
|| checkContentUriPermissionFullUnlocked(grantUri, uid,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- boolean hasPermission =
- requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_READ_OR_WRITE
- ? (readMet || writeMet) : (readMet && writeMet);
+ return requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_READ_OR_WRITE
+ ? (readMet || writeMet) : (readMet && writeMet);
+ }
- if (!hasPermission) {
- throw new SecurityException("You can't launch this activity because you don't have the"
- + " required " + ActivityInfo.requiredContentUriPermissionToShortString(
- requireContentUriPermissionFromCaller) + " access to " + grantUri.uri);
+ private void tryAddingContentUriWithoutCallerReadPermissionWhenAttributeIsNoneUnlocked(
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ GrantUri grantUri, int callingUid, Integer requestHashCode) {
+ // We're interested in requireContentUriPermissionFromCaller that is set to
+ // CONTENT_URI_PERMISSION_NONE and content URIs. Hence, ignore if
+ // requireContentUriPermissionFromCaller is not set to CONTENT_URI_PERMISSION_NONE or the
+ // URI is a non-content URI.
+ if (requireContentUriPermissionFromCaller == null
+ || requireContentUriPermissionFromCaller != CONTENT_URI_PERMISSION_NONE
+ || !ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())
+ || requestHashCode == null) {
+ return;
+ }
+
+ if (!hasRequireContentUriPermissionFromCallerUnlocked(CONTENT_URI_PERMISSION_READ, grantUri,
+ callingUid)) {
+ synchronized (mLaunchToContentUrisWithoutCallerReadPermission) {
+ if (mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode) == null) {
+ mLaunchToContentUrisWithoutCallerReadPermission
+ .put(requestHashCode, new ArraySet<>());
+ }
+ mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode)
+ .add(grantUri.uri);
+ }
}
}
- private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(Intent intent,
- int contentUserHint, int mode, int callingUid,
- @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
+ private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStreamUnlocked(
+ Intent intent, int contentUserHint, int mode, int callingUid,
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ Integer requestHashCode) {
try {
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);
if (uri != null) {
final GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
} catch (BadParcelableException e) {
Slog.w(TAG, "Failed to unparcel an URI in EXTRA_STREAM, skipping"
@@ -759,8 +821,9 @@
if (uris != null) {
for (int i = uris.size() - 1; i >= 0; i--) {
final GrantUri grantUri = GrantUri.resolve(contentUserHint, uris.get(i), mode);
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
}
} catch (BadParcelableException e) {
@@ -769,6 +832,37 @@
}
}
+ private void notifyActivityLaunchRequestCompletedUnlocked(Integer requestHashCode,
+ boolean isSuccessfulLaunch, String intentAction, int callingUid,
+ String callingActivityName, int calleeUid, String calleeActivityName,
+ boolean isStartActivityForResult) {
+ ArraySet<Uri> contentUris;
+ synchronized (mLaunchToContentUrisWithoutCallerReadPermission) {
+ contentUris = mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode);
+ mLaunchToContentUrisWithoutCallerReadPermission.remove(requestHashCode);
+ }
+ if (!isSuccessfulLaunch || contentUris == null) return;
+
+ final String[] authorities = new String[contentUris.size()];
+ final String[] schemes = new String[contentUris.size()];
+ for (int i = contentUris.size() - 1; i >= 0; i--) {
+ Uri uri = contentUris.valueAt(i);
+ authorities[i] = uri.getAuthority();
+ schemes[i] = uri.getScheme();
+ }
+ FrameworkStatsLog.write(CONTENT_OR_FILE_URI_EVENT_REPORTED,
+ CONTENT_OR_FILE_URI_EVENT_REPORTED__EVENT_TYPE__CONTENT_URI_WITHOUT_CALLER_READ_PERMISSION,
+ intentAction,
+ callingUid,
+ callingActivityName,
+ calleeUid,
+ calleeActivityName,
+ isStartActivityForResult,
+ String.join(",", authorities),
+ String.join(",", schemes),
+ /* uri_mime_type */ null);
+ }
+
@GuardedBy("mLock")
private void readGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
@@ -1645,23 +1739,36 @@
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId) {
return internalCheckGrantUriPermissionFromIntent(intent, callingUid, targetPkg,
- targetUserId, /* requireContentUriPermissionFromCaller */ null);
+ targetUserId, /* requireContentUriPermissionFromCaller */ null,
+ /* requestHashCode */ null);
}
@Override
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
- String targetPkg, int targetUserId, int requireContentUriPermissionFromCaller) {
+ String targetPkg, int targetUserId, int requireContentUriPermissionFromCaller,
+ int requestHashCode) {
return internalCheckGrantUriPermissionFromIntent(intent, callingUid, targetPkg,
- targetUserId, requireContentUriPermissionFromCaller);
+ targetUserId, requireContentUriPermissionFromCaller, requestHashCode);
+ }
+
+ @Override
+ public void notifyActivityLaunchRequestCompleted(int requestHashCode,
+ boolean isSuccessfulLaunch, String intentAction, int callingUid,
+ String callingActivityName, int calleeUid, String calleeActivityName,
+ boolean isStartActivityForResult) {
+ UriGrantsManagerService.this.notifyActivityLaunchRequestCompletedUnlocked(
+ requestHashCode, isSuccessfulLaunch, intentAction, callingUid,
+ callingActivityName, calleeUid, calleeActivityName,
+ isStartActivityForResult);
}
private NeededUriGrants internalCheckGrantUriPermissionFromIntent(Intent intent,
int callingUid, String targetPkg, int targetUserId,
- @Nullable Integer requireContentUriPermissionFromCaller) {
+ @Nullable Integer requireContentUriPermissionFromCaller, Integer requestHashCode) {
final int mode = (intent != null) ? intent.getFlags() : 0;
return UriGrantsManagerService.this.checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, intent, mode, null, targetUserId,
- requireContentUriPermissionFromCaller);
+ requireContentUriPermissionFromCaller, requestHashCode);
}
@Override
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index ab4a4d8..4c1e16c 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -128,15 +128,20 @@
* before the release callback.
*/
boolean runVibrationOnVibrationThread(VibrationStepConductor conductor) {
- synchronized (mLock) {
- if (mRequestedActiveConductor != null) {
- Slog.wtf(TAG, "Attempt to start vibration when one already running");
- return false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrationOnVibrationThread");
+ try {
+ synchronized (mLock) {
+ if (mRequestedActiveConductor != null) {
+ Slog.wtf(TAG, "Attempt to start vibration when one already running");
+ return false;
+ }
+ mRequestedActiveConductor = conductor;
+ mLock.notifyAll();
}
- mRequestedActiveConductor = conductor;
- mLock.notifyAll();
+ return true;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- return true;
}
@Override
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 4fc0b74..3c47850 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
@@ -123,21 +124,26 @@
/** Reruns the query to the vibrator to load the {@link VibratorInfo}, if not yet successful. */
public void reloadVibratorInfoIfNeeded() {
- // Early check outside lock, for quick return.
- if (mVibratorInfoLoadSuccessful) {
- return;
- }
- synchronized (mLock) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#reloadVibratorInfoIfNeeded");
+ try {
+ // Early check outside lock, for quick return.
if (mVibratorInfoLoadSuccessful) {
return;
}
- int vibratorId = mVibratorInfo.getId();
- VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
- mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
- mVibratorInfo = vibratorInfoBuilder.build();
- if (!mVibratorInfoLoadSuccessful) {
- Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
+ synchronized (mLock) {
+ if (mVibratorInfoLoadSuccessful) {
+ return;
+ }
+ int vibratorId = mVibratorInfo.getId();
+ VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
+ mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
+ mVibratorInfo = vibratorInfoBuilder.build();
+ if (!mVibratorInfoLoadSuccessful) {
+ Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -193,8 +199,13 @@
/** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
public boolean isAvailable() {
- synchronized (mLock) {
- return mNativeWrapper.isAvailable();
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#isAvailable");
+ try {
+ synchronized (mLock) {
+ return mNativeWrapper.isAvailable();
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -204,12 +215,17 @@
* <p>This will affect the state of {@link #isUnderExternalControl()}.
*/
public void setExternalControl(boolean externalControl) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
- return;
- }
- synchronized (mLock) {
- mIsUnderExternalControl = externalControl;
- mNativeWrapper.setExternalControl(externalControl);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "setExternalControl(" + externalControl + ")");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ return;
+ }
+ synchronized (mLock) {
+ mIsUnderExternalControl = externalControl;
+ mNativeWrapper.setExternalControl(externalControl);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -218,28 +234,38 @@
* if given {@code effect} is {@code null}.
*/
public void updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
- return;
- }
- synchronized (mLock) {
- if (prebaked == null) {
- mNativeWrapper.alwaysOnDisable(id);
- } else {
- mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
- prebaked.getEffectStrength());
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#updateAlwaysOn");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ return;
}
+ synchronized (mLock) {
+ if (prebaked == null) {
+ mNativeWrapper.alwaysOnDisable(id);
+ } else {
+ mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
+ prebaked.getEffectStrength());
+ }
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
/** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */
public void setAmplitude(float amplitude) {
- synchronized (mLock) {
- if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
- mNativeWrapper.setAmplitude(amplitude);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#setAmplitude");
+ try {
+ synchronized (mLock) {
+ if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ mNativeWrapper.setAmplitude(amplitude);
+ }
+ if (mIsVibrating) {
+ mCurrentAmplitude = amplitude;
+ }
}
- if (mIsVibrating) {
- mCurrentAmplitude = amplitude;
- }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -253,13 +279,18 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(long milliseconds, long vibrationId) {
- synchronized (mLock) {
- long duration = mNativeWrapper.on(milliseconds, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on");
+ try {
+ synchronized (mLock) {
+ long duration = mNativeWrapper.on(milliseconds, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
}
- return duration;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -273,6 +304,7 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(VibrationEffect.VendorEffect vendorEffect, long vibrationId) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (vendor)");
synchronized (mLock) {
Parcel vendorData = Parcel.obtain();
try {
@@ -288,6 +320,7 @@
return duration;
} finally {
vendorData.recycle();
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
}
@@ -302,14 +335,19 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(PrebakedSegment prebaked, long vibrationId) {
- synchronized (mLock) {
- long duration = mNativeWrapper.perform(prebaked.getEffectId(),
- prebaked.getEffectStrength(), vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (Prebaked)");
+ try {
+ synchronized (mLock) {
+ long duration = mNativeWrapper.perform(prebaked.getEffectId(),
+ prebaked.getEffectStrength(), vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
}
- return duration;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -323,16 +361,21 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(PrimitiveSegment[] primitives, long vibrationId) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
- return 0;
- }
- synchronized (mLock) {
- long duration = mNativeWrapper.compose(primitives, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (Primitive)");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ return 0;
}
- return duration;
+ synchronized (mLock) {
+ long duration = mNativeWrapper.compose(primitives, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -345,17 +388,22 @@
* @return The duration of the effect playing, or 0 if unsupported.
*/
public long on(RampSegment[] primitives, long vibrationId) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
- return 0;
- }
- synchronized (mLock) {
- int braking = mVibratorInfo.getDefaultBraking();
- long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (PWLE)");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
+ return 0;
}
- return duration;
+ synchronized (mLock) {
+ int braking = mVibratorInfo.getDefaultBraking();
+ long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -365,10 +413,15 @@
* <p>This will affect the state of {@link #isVibrating()}.
*/
public void off() {
- synchronized (mLock) {
- mNativeWrapper.off();
- mCurrentAmplitude = 0;
- notifyListenerOnVibrating(false);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#off");
+ try {
+ synchronized (mLock) {
+ mNativeWrapper.off();
+ mCurrentAmplitude = 0;
+ notifyListenerOnVibrating(false);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 799934a..899f0b1 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -462,20 +462,31 @@
@Override // Binder call
public void performHapticFeedback(int uid, int deviceId, String opPkg, int constant,
String reason, int flags, int privFlags) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedback");
// Note that the `performHapticFeedback` method does not take a token argument from the
// caller, and instead, uses this service as the token. This is to mitigate performance
// impact that would otherwise be caused due to marshal latency. Haptic feedback effects are
// short-lived, so we don't need to cancel when the process dies.
- performHapticFeedbackInternal(uid, deviceId, opPkg, constant, reason, /* token= */
- this, flags, privFlags);
+ try {
+ performHapticFeedbackInternal(uid, deviceId, opPkg, constant, reason, /* token= */
+ this, flags, privFlags);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override // Binder call
public void performHapticFeedbackForInputDevice(int uid, int deviceId, String opPkg,
int constant, int inputDeviceId, int inputSource, String reason, int flags,
int privFlags) {
- performHapticFeedbackForInputDeviceInternal(uid, deviceId, opPkg, constant, inputDeviceId,
- inputSource, reason, /* token= */ this, flags, privFlags);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedbackForInputDevice");
+ try {
+ performHapticFeedbackForInputDeviceInternal(uid, deviceId, opPkg, constant,
+ inputDeviceId,
+ inputSource, reason, /* token= */ this, flags, privFlags);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
/**
@@ -919,30 +930,25 @@
@GuardedBy("mLock")
@Nullable
private Vibration.EndInfo startVibrationOnThreadLocked(VibrationStepConductor conductor) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationThreadLocked");
- try {
- HalVibration vib = conductor.getVibration();
- int mode = startAppOpModeLocked(vib.callerInfo);
- switch (mode) {
- case AppOpsManager.MODE_ALLOWED:
- Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- // Make sure mCurrentVibration is set while triggering the VibrationThread.
- mCurrentVibration = conductor;
- if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
- // Shouldn't happen. The method call already logs a wtf.
- mCurrentVibration = null; // Aborted.
- return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
- }
- return null;
- case AppOpsManager.MODE_ERRORED:
- Slog.w(TAG, "Start AppOpsManager operation errored for uid "
- + vib.callerInfo.uid);
- return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
- default:
- return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ HalVibration vib = conductor.getVibration();
+ int mode = startAppOpModeLocked(vib.callerInfo);
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+ // Make sure mCurrentVibration is set while triggering the VibrationThread.
+ mCurrentVibration = conductor;
+ if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
+ // Shouldn't happen. The method call already logs a wtf.
+ mCurrentVibration = null; // Aborted.
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
+ }
+ return null;
+ case AppOpsManager.MODE_ERRORED:
+ Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+ + vib.callerInfo.uid);
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
+ default:
+ return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
}
}
@@ -1050,21 +1056,16 @@
@GuardedBy("mLock")
private void reportFinishedVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- try {
- HalVibration vib = mCurrentVibration.getVibration();
- if (DEBUG) {
- Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
- + vibrationEndInfo);
- }
- // DO NOT write metrics at this point, wait for the VibrationThread to report the
- // vibration was released, after all cleanup. The metrics will be reported then.
- endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
- finishAppOpModeLocked(vib.callerInfo);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ HalVibration vib = mCurrentVibration.getVibration();
+ if (DEBUG) {
+ Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
+ + vibrationEndInfo);
}
+ // DO NOT write metrics at this point, wait for the VibrationThread to report the
+ // vibration was released, after all cleanup. The metrics will be reported then.
+ endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
+ finishAppOpModeLocked(vib.callerInfo);
}
private void onSyncedVibrationComplete(long vibrationId) {
@@ -1418,40 +1419,34 @@
@GuardedBy("mLock")
@Nullable
- private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked(
- CombinedVibration effect) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "fixupAlwaysOnEffectsLocked");
- try {
- SparseArray<VibrationEffect> effects;
- if (effect instanceof CombinedVibration.Mono) {
- VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect();
- effects = transformAllVibratorsLocked(unused -> syncedEffect);
- } else if (effect instanceof CombinedVibration.Stereo) {
- effects = ((CombinedVibration.Stereo) effect).getEffects();
- } else {
- // Only synced combinations can be used for always-on effects.
- return null;
- }
- SparseArray<PrebakedSegment> result = new SparseArray<>();
- for (int i = 0; i < effects.size(); i++) {
- PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i));
- if (prebaked == null) {
- Slog.e(TAG, "Only prebaked effects supported for always-on.");
- return null;
- }
- int vibratorId = effects.keyAt(i);
- VibratorController vibrator = mVibrators.get(vibratorId);
- if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
- result.put(vibratorId, prebaked);
- }
- }
- if (result.size() == 0) {
- return null;
- }
- return result;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked(CombinedVibration effect) {
+ SparseArray<VibrationEffect> effects;
+ if (effect instanceof CombinedVibration.Mono) {
+ VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect();
+ effects = transformAllVibratorsLocked(unused -> syncedEffect);
+ } else if (effect instanceof CombinedVibration.Stereo) {
+ effects = ((CombinedVibration.Stereo) effect).getEffects();
+ } else {
+ // Only synced combinations can be used for always-on effects.
+ return null;
}
+ SparseArray<PrebakedSegment> result = new SparseArray<>();
+ for (int i = 0; i < effects.size(); i++) {
+ PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i));
+ if (prebaked == null) {
+ Slog.e(TAG, "Only prebaked effects supported for always-on.");
+ return null;
+ }
+ int vibratorId = effects.keyAt(i);
+ VibratorController vibrator = mVibrators.get(vibratorId);
+ if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ result.put(vibratorId, prebaked);
+ }
+ }
+ if (result.size() == 0) {
+ return null;
+ }
+ return result;
}
@Nullable
@@ -1580,25 +1575,42 @@
@Override
public boolean prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds) {
- if ((mCapabilities & requiredCapabilities) != requiredCapabilities) {
- // This sync step requires capabilities this device doesn't have, skipping sync...
- return false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "prepareSyncedVibration");
+ try {
+ if ((mCapabilities & requiredCapabilities) != requiredCapabilities) {
+ // This sync step requires capabilities this device doesn't have, skipping
+ // sync...
+ return false;
+ }
+ return mNativeWrapper.prepareSynced(vibratorIds);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- return mNativeWrapper.prepareSynced(vibratorIds);
}
@Override
public boolean triggerSyncedVibration(long vibrationId) {
- return mNativeWrapper.triggerSynced(vibrationId);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "triggerSyncedVibration");
+ try {
+ return mNativeWrapper.triggerSynced(vibrationId);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override
public void cancelSyncedVibration() {
- mNativeWrapper.cancelSynced();
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "cancelSyncedVibration");
+ try {
+ mNativeWrapper.cancelSynced();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override
public void noteVibratorOn(int uid, long duration) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "noteVibratorOn");
try {
if (duration <= 0) {
// Tried to turn vibrator ON and got:
@@ -1616,16 +1628,21 @@
mFrameworkStatsLogger.writeVibratorStateOnAsync(uid, duration);
} catch (RemoteException e) {
Slog.e(TAG, "Error logging VibratorStateChanged to ON", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@Override
public void noteVibratorOff(int uid) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "noteVibratorOff");
try {
mBatteryStatsService.noteVibratorOff(uid);
mFrameworkStatsLogger.writeVibratorStateOffAsync(uid);
} catch (RemoteException e) {
Slog.e(TAG, "Error logging VibratorStateChanged to OFF", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -1634,11 +1651,16 @@
if (DEBUG) {
Slog.d(TAG, "Vibration " + vibrationId + " finished with " + vibrationEndInfo);
}
- synchronized (mLock) {
- if (mCurrentVibration != null
- && mCurrentVibration.getVibration().id == vibrationId) {
- reportFinishedVibrationLocked(vibrationEndInfo);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onVibrationCompleted");
+ try {
+ synchronized (mLock) {
+ if (mCurrentVibration != null
+ && mCurrentVibration.getVibration().id == vibrationId) {
+ reportFinishedVibrationLocked(vibrationEndInfo);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -1647,34 +1669,40 @@
if (DEBUG) {
Slog.d(TAG, "VibrationThread released after finished vibration");
}
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Processing VibrationThread released callback");
- }
- if (Build.IS_DEBUGGABLE && mCurrentVibration != null
- && mCurrentVibration.getVibration().id != vibrationId) {
- Slog.wtf(TAG, TextUtils.formatSimple(
- "VibrationId mismatch on release. expected=%d, released=%d",
- mCurrentVibration.getVibration().id, vibrationId));
- }
- if (mCurrentVibration != null) {
- // This is when we consider the current vibration complete, so report metrics.
- mFrameworkStatsLogger.writeVibrationReportedAsync(
- mCurrentVibration.getVibration().getStatsInfo(
- /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
- mCurrentVibration = null;
- }
- if (mNextVibration != null) {
- VibrationStepConductor nextConductor = mNextVibration;
- mNextVibration = null;
- Vibration.EndInfo vibrationEndInfo = startVibrationOnThreadLocked(
- nextConductor);
- if (vibrationEndInfo != null) {
- // Failed to start the vibration, end it and report metrics right away.
- endVibrationLocked(nextConductor.getVibration(),
- vibrationEndInfo, /* shouldWriteStats= */ true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onVibrationThreadReleased: " + vibrationId);
+ try {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "Processing VibrationThread released callback");
+ }
+ if (Build.IS_DEBUGGABLE && mCurrentVibration != null
+ && mCurrentVibration.getVibration().id != vibrationId) {
+ Slog.wtf(TAG, TextUtils.formatSimple(
+ "VibrationId mismatch on release. expected=%d, released=%d",
+ mCurrentVibration.getVibration().id, vibrationId));
+ }
+ if (mCurrentVibration != null) {
+ // This is when we consider the current vibration complete, so report
+ // metrics.
+ mFrameworkStatsLogger.writeVibrationReportedAsync(
+ mCurrentVibration.getVibration().getStatsInfo(
+ /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
+ mCurrentVibration = null;
+ }
+ if (mNextVibration != null) {
+ VibrationStepConductor nextConductor = mNextVibration;
+ mNextVibration = null;
+ Vibration.EndInfo vibrationEndInfo = startVibrationOnThreadLocked(
+ nextConductor);
+ if (vibrationEndInfo != null) {
+ // Failed to start the vibration, end it and report metrics right away.
+ endVibrationLocked(nextConductor.getVibration(),
+ vibrationEndInfo, /* shouldWriteStats= */ true);
+ }
}
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
}
@@ -1917,22 +1945,17 @@
@GuardedBy("mLock")
private void endExternalVibrateLocked(Vibration.EndInfo vibrationEndInfo,
boolean continueExternalControl) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked");
- try {
- if (mCurrentExternalVibration == null) {
- return;
- }
- mCurrentExternalVibration.unlinkToDeath();
- if (!continueExternalControl) {
- setExternalControl(false, mCurrentExternalVibration.stats);
- }
- // The external control was turned off, end it and report metrics right away.
- endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
- /* shouldWriteStats= */ true);
- mCurrentExternalVibration = null;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ if (mCurrentExternalVibration == null) {
+ return;
}
+ mCurrentExternalVibration.unlinkToDeath();
+ if (!continueExternalControl) {
+ setExternalControl(false, mCurrentExternalVibration.stats);
+ }
+ // The external control was turned off, end it and report metrics right away.
+ endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ mCurrentExternalVibration = null;
}
private HapticFeedbackVibrationProvider getHapticVibrationProvider() {
@@ -1987,143 +2010,160 @@
@Override
public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {
- // Create Vibration.Stats as close to the received request as possible, for tracking.
- ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
- // Mute the request until we run all the checks and accept the vibration.
- externalVibration.muteScale();
- boolean alreadyUnderExternalControl = false;
- boolean waitForCompletion = false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onExternalVibrationStart");
+ try {
+ // Create Vibration.Stats as close to the received request as possible, for
+ // tracking.
+ ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
+ // Mute the request until we run all the checks and accept the vibration.
+ externalVibration.muteScale();
+ boolean alreadyUnderExternalControl = false;
+ boolean waitForCompletion = false;
- synchronized (mLock) {
- if (!hasExternalControlCapability()) {
- endVibrationLocked(externalVibration,
- new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ synchronized (mLock) {
+ if (!hasExternalControlCapability()) {
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
- vib.getUid(), -1 /*owningUid*/, true /*exported*/)
- != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
- + " tried to play externally controlled vibration"
- + " without VIBRATE permission, ignoring.");
- endVibrationLocked(externalVibration,
- new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.VIBRATE,
+ vib.getUid(), -1 /*owningUid*/, true /*exported*/)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
+ + " tried to play externally controlled vibration"
+ + " without VIBRATE permission, ignoring.");
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
- externalVibration.callerInfo);
+ Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
+ externalVibration.callerInfo);
- if (vibrationEndInfo == null
- && mCurrentExternalVibration != null
- && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
- // We are already playing this external vibration, so we can return the same
- // scale calculated in the previous call to this method.
- return mCurrentExternalVibration.getScale();
- }
+ if (vibrationEndInfo == null
+ && mCurrentExternalVibration != null
+ && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
+ // We are already playing this external vibration, so we can return the same
+ // scale calculated in the previous call to this method.
+ return mCurrentExternalVibration.getScale();
+ }
- if (vibrationEndInfo == null) {
- // Check if ongoing vibration is more important than this vibration.
- vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
- }
+ if (vibrationEndInfo == null) {
+ // Check if ongoing vibration is more important than this vibration.
+ vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
+ }
- if (vibrationEndInfo != null) {
- endVibrationLocked(externalVibration, vibrationEndInfo,
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ if (vibrationEndInfo != null) {
+ endVibrationLocked(externalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- if (mCurrentExternalVibration == null) {
- // If we're not under external control right now, then cancel any normal
- // vibration that may be playing and ready the vibrator for external control.
- if (mCurrentVibration != null) {
+ if (mCurrentExternalVibration == null) {
+ // If we're not under external control right now, then cancel any normal
+ // vibration that may be playing and ready the vibrator for external
+ // control.
+ if (mCurrentVibration != null) {
+ externalVibration.stats.reportInterruptedAnotherVibration(
+ mCurrentVibration.getVibration().callerInfo);
+ clearNextVibrationLocked(
+ new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
+ externalVibration.callerInfo));
+ mCurrentVibration.notifyCancelled(
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
+ externalVibration.callerInfo),
+ /* immediate= */ true);
+ waitForCompletion = true;
+ }
+ } else {
+ // At this point we have an externally controlled vibration playing already.
+ // Since the interface defines that only one externally controlled
+ // vibration can
+ // play at a time, we need to first mute the ongoing vibration and then
+ // return
+ // a scale from this function for the new one, so we can be assured that the
+ // ongoing will be muted in favor of the new vibration.
+ //
+ // Note that this doesn't support multiple concurrent external controls,
+ // as we would need to mute the old one still if it came from a different
+ // controller.
+ alreadyUnderExternalControl = true;
+ mCurrentExternalVibration.notifyEnded();
externalVibration.stats.reportInterruptedAnotherVibration(
- mCurrentVibration.getVibration().callerInfo);
- clearNextVibrationLocked(
- new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
- externalVibration.callerInfo));
- mCurrentVibration.notifyCancelled(
+ mCurrentExternalVibration.callerInfo);
+ endExternalVibrateLocked(
new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
externalVibration.callerInfo),
- /* immediate= */ true);
- waitForCompletion = true;
+ /* continueExternalControl= */ true);
}
- } else {
- // At this point we have an externally controlled vibration playing already.
- // Since the interface defines that only one externally controlled vibration can
- // play at a time, we need to first mute the ongoing vibration and then return
- // a scale from this function for the new one, so we can be assured that the
- // ongoing will be muted in favor of the new vibration.
- //
- // Note that this doesn't support multiple concurrent external controls, as we
- // would need to mute the old one still if it came from a different controller.
- alreadyUnderExternalControl = true;
- mCurrentExternalVibration.notifyEnded();
- externalVibration.stats.reportInterruptedAnotherVibration(
- mCurrentExternalVibration.callerInfo);
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
- externalVibration.callerInfo),
- /* continueExternalControl= */ true);
- }
- VibrationAttributes attrs = fixupVibrationAttributes(vib.getVibrationAttributes(),
- /* effect= */ null);
- if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
- // Force update of user settings before checking if this vibration effect should
- // be ignored or scaled.
- mVibrationSettings.update();
- }
-
- mCurrentExternalVibration = externalVibration;
- externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
- externalVibration.scale(mVibrationScaler, attrs.getUsage());
- }
-
- if (waitForCompletion) {
- if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
- Slog.e(TAG, "Timed out waiting for vibration to cancel");
- synchronized (mLock) {
- // Trigger endExternalVibrateLocked to unlink to death recipient.
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
- /* continueExternalControl= */ false);
- // Mute the request, vibration will be ignored.
- externalVibration.muteScale();
+ VibrationAttributes attrs = fixupVibrationAttributes(
+ vib.getVibrationAttributes(),
+ /* effect= */ null);
+ if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+ // Force update of user settings before checking if this vibration effect
+ // should be ignored or scaled.
+ mVibrationSettings.update();
}
- return externalVibration.getScale();
+
+ mCurrentExternalVibration = externalVibration;
+ externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
+ externalVibration.scale(mVibrationScaler, attrs.getUsage());
}
- }
- if (!alreadyUnderExternalControl) {
+
+ if (waitForCompletion) {
+ if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
+ Slog.e(TAG, "Timed out waiting for vibration to cancel");
+ synchronized (mLock) {
+ // Trigger endExternalVibrateLocked to unlink to death recipient.
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
+ /* continueExternalControl= */ false);
+ // Mute the request, vibration will be ignored.
+ externalVibration.muteScale();
+ }
+ return externalVibration.getScale();
+ }
+ }
+ if (!alreadyUnderExternalControl) {
+ if (DEBUG) {
+ Slog.d(TAG, "Vibrator going under external control.");
+ }
+ setExternalControl(true, externalVibration.stats);
+ }
if (DEBUG) {
- Slog.d(TAG, "Vibrator going under external control.");
+ Slog.d(TAG, "Playing external vibration: " + vib);
}
- setExternalControl(true, externalVibration.stats);
+ // Vibrator will start receiving data from external channels after this point.
+ // Report current time as the vibration start time, for debugging.
+ externalVibration.stats.reportStarted();
+ return externalVibration.getScale();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- if (DEBUG) {
- Slog.d(TAG, "Playing external vibration: " + vib);
- }
- // Vibrator will start receiving data from external channels after this point.
- // Report current time as the vibration start time, for debugging.
- externalVibration.stats.reportStarted();
- return externalVibration.getScale();
}
@Override
public void onExternalVibrationStop(ExternalVibration vib) {
- synchronized (mLock) {
- if (mCurrentExternalVibration != null
- && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
- if (DEBUG) {
- Slog.d(TAG, "Stopping external vibration: " + vib);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onExternalVibrationStop");
+ try {
+ synchronized (mLock) {
+ if (mCurrentExternalVibration != null
+ && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stopping external vibration: " + vib);
+ }
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.FINISHED),
+ /* continueExternalControl= */ false);
}
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.FINISHED),
- /* continueExternalControl= */ false);
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f52a74f..8c23eaa 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2641,7 +2641,7 @@
return true;
}
// Only do transfer after transaction has done when starting window exist.
- if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) {
+ if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommitCount > 0) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT;
return true;
}
@@ -2804,9 +2804,11 @@
@Override
void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
+ // Only add once per transition.
+ final boolean added = wcAwaitingCommit.contains(this);
super.waitForSyncTransactionCommit(wcAwaitingCommit);
- if (mStartingData != null) {
- mStartingData.mWaitForSyncTransactionCommit = true;
+ if (!added && mStartingData != null) {
+ mStartingData.mWaitForSyncTransactionCommitCount++;
}
}
@@ -2817,7 +2819,7 @@
return;
}
final StartingData lastData = mStartingData;
- lastData.mWaitForSyncTransactionCommit = false;
+ lastData.mWaitForSyncTransactionCommitCount--;
if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_REMOVE_DIRECTLY) {
removeStartingWindowAnimation(lastData.mPrepareRemoveAnimation);
} else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
@@ -2847,7 +2849,7 @@
final boolean animate;
final boolean hasImeSurface;
if (mStartingData != null) {
- if (mStartingData.mWaitForSyncTransactionCommit
+ if (mStartingData.mWaitForSyncTransactionCommitCount > 0
|| mSyncState != SYNC_STATE_NONE) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
mStartingData.mPrepareRemoveAnimation = prepareAnimation;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1822a80..bc11bac 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -603,7 +603,8 @@
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
activityInfo.applicationInfo.packageName,
UserHandle.getUserId(activityInfo.applicationInfo.uid),
- activityInfo.requireContentUriPermissionFromCaller);
+ activityInfo.requireContentUriPermissionFromCaller,
+ /* requestHashCode */ this.hashCode());
} else {
intentGrants = supervisor.mService.mUgmInternal
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
@@ -717,6 +718,9 @@
* @return The starter result.
*/
int execute() {
+ // Required for logging ContentOrFileUriEventReported in the finally block.
+ String callerActivityName = null;
+ ActivityRecord launchingRecord = null;
try {
onExecutionStarted();
@@ -737,6 +741,7 @@
? Binder.getCallingUid() : mRequest.realCallingUid;
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
mRequest.intent, caller, callingUid);
+ callerActivityName = caller != null ? caller.info.name : null;
}
if (mRequest.intent != null) {
@@ -812,7 +817,7 @@
final ActivityOptions originalOptions = mRequest.activityOptions != null
? mRequest.activityOptions.getOriginalOptions() : null;
// Only track the launch time of activity that will be resumed.
- final ActivityRecord launchingRecord = mDoResume ? mLastStartActivityRecord : null;
+ launchingRecord = mDoResume ? mLastStartActivityRecord : null;
// If the new record is the one that started, a new activity has created.
final boolean newActivityCreated = mStartActivity == launchingRecord;
// Notify ActivityMetricsLogger that the activity has launched.
@@ -828,6 +833,23 @@
return getExternalResult(res);
}
} finally {
+ // Notify UriGrantsManagerService that activity launch completed. Required for logging
+ // the ContentOrFileUriEventReported message.
+ mSupervisor.mService.mUgmInternal.notifyActivityLaunchRequestCompleted(
+ mRequest.hashCode(),
+ // isSuccessfulLaunch
+ launchingRecord != null,
+ // Intent action
+ mRequest.intent != null ? mRequest.intent.getAction() : null,
+ mRequest.realCallingUid,
+ callerActivityName,
+ // Callee UID
+ mRequest.activityInfo != null
+ ? mRequest.activityInfo.applicationInfo.uid : INVALID_UID,
+ // Callee Activity name
+ mRequest.activityInfo != null ? mRequest.activityInfo.name : null,
+ // isStartActivityForResult
+ launchingRecord != null && launchingRecord.resultTo != null);
onExecutionComplete();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 49ca698..3d5b273 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6207,6 +6207,8 @@
@Override
public void onProcessAdded(WindowProcessController proc) {
synchronized (mGlobalLockWithoutBoost) {
+ mPackageConfigPersister.updateConfigIfNeeded(
+ proc, proc.mUserId, proc.mInfo.packageName);
mProcessNames.put(proc.mName, proc.mUid, proc);
}
}
diff --git a/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java b/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
index 852ce04..9c861fe 100644
--- a/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
@@ -16,16 +16,13 @@
package com.android.server.wm;
-import static android.os.StrictMode.setThreadPolicy;
-
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Environment;
-import android.os.StrictMode;
-import android.os.StrictMode.ThreadPolicy;
import android.util.AtomicFile;
import android.util.Slog;
@@ -122,7 +119,7 @@
final File prefFiles = new File(configFolder, letterboxConfigurationFileName);
mConfigurationFile = new AtomicFile(prefFiles);
mPersisterQueue = persisterQueue;
- runWithDiskReadsThreadPolicy(this::readCurrentConfiguration);
+ readCurrentConfiguration();
}
/**
@@ -212,6 +209,7 @@
mDefaultTabletopModeReachabilitySupplier.get();
}
+ @MainThread
private void readCurrentConfiguration() {
if (!mConfigurationFile.exists()) {
useDefaultValue();
@@ -272,20 +270,6 @@
}
}
- // The LetterboxConfigurationDeviceConfig needs to access the
- // file with the current reachability position once when the
- // device boots. Because DisplayThread uses allowIo=false
- // accessing a file triggers a DiskReadViolation.
- // Here we use StrictMode to allow the current thread to read
- // the AtomicFile once in the current thread restoring the
- // original ThreadPolicy after that.
- private void runWithDiskReadsThreadPolicy(Runnable runnable) {
- final ThreadPolicy currentPolicy = StrictMode.getThreadPolicy();
- setThreadPolicy(new ThreadPolicy.Builder().permitDiskReads().build());
- runnable.run();
- setThreadPolicy(currentPolicy);
- }
-
private static class UpdateValuesCommand implements
PersisterQueue.WriteQueueItem<UpdateValuesCommand> {
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 0646fb7..dd86a14 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -2002,6 +2002,7 @@
final Transition prepareOpen = migrateBackTransition && !tc.isCollecting()
? tc.createTransition(TRANSIT_PREPARE_BACK_NAVIGATION) : null;
+ DisplayContent commonDisplay = null;
for (int i = affects.size() - 1; i >= 0; --i) {
final ActivityRecord activity = affects.get(i);
if (!migrateBackTransition && !activity.isVisibleRequested()) {
@@ -2024,13 +2025,15 @@
activity.mTaskSupervisor.mStoppingActivities.remove(activity);
if (!migrateBackTransition) {
- activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
- true /* notifyClients */);
+ commonDisplay = activity.getDisplayContent();
} else if (activity.shouldBeVisible()) {
activity.ensureActivityConfiguration(true /* ignoreVisibility */);
activity.makeVisibleIfNeeded(null /* starting */, true /* notifyToClient */);
}
}
+ if (commonDisplay != null) {
+ commonDisplay.ensureActivitiesVisible(null /* starting */, true /* notifyClients */);
+ }
if (prepareOpen != null) {
if (prepareOpen.hasChanges()) {
tc.requestStartTransition(prepareOpen,
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index dda39a6..e3232e0 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -16,20 +16,28 @@
package com.android.server.wm;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.CameraCompatTaskInfo;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.view.DisplayInfo;
+import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
@@ -172,11 +180,35 @@
}
private static int getCameraCompatMode(@NonNull ActivityRecord topActivity) {
- return switch (topActivity.getRequestedConfigurationOrientation()) {
- case ORIENTATION_PORTRAIT -> CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT;
- case ORIENTATION_LANDSCAPE -> CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE;
- default -> CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
- };
+ final int appOrientation = topActivity.getRequestedConfigurationOrientation();
+ // It is very important to check the original (actual) display rotation, and not the
+ // sandboxed rotation that camera compat treatment sets.
+ final DisplayInfo displayInfo = topActivity.mWmService.mDisplayManagerInternal
+ .getDisplayInfo(topActivity.getDisplayId());
+ // This treatment targets only devices with portrait natural orientation, which most tablets
+ // have.
+ // TODO(b/365725400): handle landscape natural orientation.
+ if (displayInfo.getNaturalHeight() > displayInfo.getNaturalWidth()) {
+ if (appOrientation == ORIENTATION_PORTRAIT) {
+ if (isDisplayRotationPortrait(displayInfo.rotation)) {
+ return CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
+ } else {
+ return CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+ }
+ } else if (appOrientation == ORIENTATION_LANDSCAPE) {
+ if (isDisplayRotationPortrait(displayInfo.rotation)) {
+ return CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
+ } else {
+ return CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
+ }
+ }
+ }
+
+ return CAMERA_COMPAT_FREEFORM_NONE;
+ }
+
+ private static boolean isDisplayRotationPortrait(@Surface.Rotation int displayRotation) {
+ return displayRotation == ROTATION_0 || displayRotation == ROTATION_180;
}
/**
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index c3db7dd..cc6904f 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -37,8 +37,7 @@
import android.os.SystemProperties;
import android.util.Size;
import android.view.Gravity;
-
-import com.android.server.wm.utils.DesktopModeFlagsUtil;
+import android.window.flags.DesktopModeFlags;
import java.util.function.Consumer;
@@ -104,7 +103,7 @@
final TaskDisplayArea displayArea = task.getDisplayArea();
final Rect screenBounds = displayArea.getBounds();
final Size idealSize = calculateIdealSize(screenBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- if (!DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(activity.mWmService.mContext)) {
+ if (!DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(activity.mWmService.mContext)) {
return centerInScreen(idealSize, screenBounds);
}
if (activity.mAppCompatController.getAppCompatAspectRatioOverrides()
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index e0c0c2c..61fbb96 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -19,10 +19,10 @@
import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;
+import android.window.flags.DesktopModeFlags;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wm.utils.DesktopModeFlagsUtil;
/**
* Constants for desktop mode feature
@@ -36,7 +36,7 @@
/** Whether desktop mode is enabled. */
static boolean isDesktopModeEnabled(@NonNull Context context) {
- return DesktopModeFlagsUtil.DESKTOP_WINDOWING_MODE.isEnabled(context);
+ return DesktopModeFlags.DESKTOP_WINDOWING_MODE.isEnabled(context);
}
/**
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index faf6dc6..bc18895 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -109,7 +109,9 @@
// Sets the requested layer to reparent the dim to without applying it immediately
void setRequestedGeometryParent(WindowContainer<?> geometryParent) {
- mRequestedProperties.mGeometryParent = geometryParent;
+ if (geometryParent != null) {
+ mRequestedProperties.mGeometryParent = geometryParent;
+ }
}
// Sets a requested change without applying it immediately
@@ -139,9 +141,14 @@
dim.remove(t);
return;
}
+ if (!dim.mDimSurface.isValid()) {
+ Log.e(TAG, "Dimming surface " + dim.mDimSurface + " has already been released!"
+ + " Can not apply changes.");
+ return;
+ }
dim.ensureVisible(t);
- reparent(dim.mDimSurface,
+ reparent(dim,
startProperties.mGeometryParent != mRequestedProperties.mGeometryParent
? mRequestedProperties.mGeometryParent.getSurfaceControl() : null,
mRequestedProperties.mDimmingContainer != startProperties.mDimmingContainer
@@ -159,7 +166,7 @@
"%s skipping animation and directly setting alpha=%f, blur=%d",
dim, startProperties.mAlpha,
mRequestedProperties.mBlurRadius);
- setCurrentAlphaBlur(dim.mDimSurface, t);
+ setCurrentAlphaBlur(dim, t);
dim.mSkipAnimation = false;
} else {
startAnimation(t, dim, startProperties, mRequestedProperties);
@@ -186,7 +193,7 @@
synchronized (dim.mHostContainer.mWmService.mGlobalLock) {
SurfaceControl.Transaction finishTransaction =
dim.mHostContainer.getSyncTransaction();
- setCurrentAlphaBlur(dim.mDimSurface, finishTransaction);
+ setCurrentAlphaBlur(dim, finishTransaction);
if (targetAlpha == 0f && !dim.isDimming()) {
dim.remove(finishTransaction);
}
@@ -229,10 +236,11 @@
/**
* Change the geometry and relative parent of this dim layer
*/
- static void reparent(@NonNull SurfaceControl dimLayer,
+ void reparent(@NonNull Dimmer.DimState dim,
@Nullable SurfaceControl newGeometryParent,
@Nullable SurfaceControl newRelativeParent,
@NonNull SurfaceControl.Transaction t) {
+ final SurfaceControl dimLayer = dim.mDimSurface;
try {
if (newGeometryParent != null) {
t.reparent(dimLayer, newGeometryParent);
@@ -245,7 +253,8 @@
}
}
- void setCurrentAlphaBlur(@NonNull SurfaceControl sc, @NonNull SurfaceControl.Transaction t) {
+ void setCurrentAlphaBlur(@NonNull Dimmer.DimState dim, @NonNull SurfaceControl.Transaction t) {
+ final SurfaceControl sc = dim.mDimSurface;
try {
t.setAlpha(sc, mCurrentProperties.mAlpha);
t.setBackgroundBlurRadius(sc, mCurrentProperties.mBlurRadius);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 0daddc0..481ecd3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -380,7 +380,6 @@
if (android.view.inputmethod.Flags.refactorInsetsController()) {
notifyInsetsChanged();
mDisplayContent.updateSystemGestureExclusion();
- mDisplayContent.updateKeepClearAreas();
mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
}
}
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 24fb207..22c7e8c 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -69,7 +69,7 @@
* Note this isn't equal to transition playing, the period should be
* Sync finishNow -> Start transaction apply.
*/
- boolean mWaitForSyncTransactionCommit;
+ int mWaitForSyncTransactionCommitCount;
/**
* For Shell transition.
@@ -112,7 +112,7 @@
public String toString() {
return getClass().getSimpleName() + "{"
+ Integer.toHexString(System.identityHashCode(this))
- + " waitForSyncTransactionCommit=" + mWaitForSyncTransactionCommit
+ + " mWaitForSyncTransactionCommitCount=" + mWaitForSyncTransactionCommitCount
+ " removeAfterTransaction= " + mRemoveAfterTransaction
+ "}";
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3bb273c..3490b3e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3806,6 +3806,9 @@
sb.append(" aI=");
sb.append(affinityIntent.getComponent().flattenToShortString());
}
+ sb.append(" isResizeable=").append(isResizeable());
+ sb.append(" minWidth=").append(mMinWidth);
+ sb.append(" minHeight=").append(mMinHeight);
sb.append('}');
return stringName = sb.toString();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1eeb3ec..9d46529 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2875,6 +2875,15 @@
}
/**
+ * Go through the hierarchy to allow windows to request a dim if needed
+ */
+ void adjustDims() {
+ for (int i = 0; i < mChildren.size(); i++) {
+ mChildren.get(i).adjustDims();
+ }
+ }
+
+ /**
* Trigger a call to prepareSurfaces from the animation thread, such that pending transactions
* will be applied.
*/
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 459a509..33f2dd1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1186,9 +1186,13 @@
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
+ // Using SysUI context to have access to Material colors extracted from Wallpaper.
+ final AppCompatConfiguration appCompat = new AppCompatConfiguration(
+ ActivityThread.currentActivityThread().getSystemUiContext());
+
final WindowManagerService wms = main(context, im, showBootMsgs, policy, atm,
new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new,
- SurfaceControl.Builder::new);
+ SurfaceControl.Builder::new, appCompat);
WindowManagerGlobal.setWindowManagerServiceForSystemProcess(wms);
return wms;
}
@@ -1202,12 +1206,14 @@
final boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
DisplayWindowSettingsProvider displayWindowSettingsProvider,
Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+ Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ AppCompatConfiguration appCompat) {
+
final WindowManagerService[] wms = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(() ->
wms[0] = new WindowManagerService(context, im, showBootMsgs, policy, atm,
displayWindowSettingsProvider, transactionFactory,
- surfaceControlFactory), 0);
+ surfaceControlFactory, appCompat), 0);
return wms[0];
}
@@ -1231,7 +1237,8 @@
boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
DisplayWindowSettingsProvider displayWindowSettingsProvider,
Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+ Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ AppCompatConfiguration appCompat) {
installLock(this, INDEX_WINDOW);
mGlobalLock = atm.getGlobalLock();
mAtmService = atm;
@@ -1283,9 +1290,7 @@
| WindowInsets.Type.navigationBars();
}
- mAppCompatConfiguration = new AppCompatConfiguration(
- // Using SysUI context to have access to Material colors extracted from Wallpaper.
- ActivityThread.currentActivityThread().getSystemUiContext());
+ mAppCompatConfiguration = appCompat;
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 87ce866..976be4a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -357,8 +357,6 @@
}
mUseFifoUiScheduling = com.android.window.flags.Flags.fifoPriorityForMajorUiProcesses()
&& (isSysUiPackage || mAtm.isCallerRecents(uid));
-
- mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName);
}
public void setPid(int pid) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 021be57..1640ad3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2754,10 +2754,16 @@
* @param outRegion The region to update.
*/
private void updateRegionForModalActivityWindow(Region outRegion) {
- // If the inner bounds of letterbox is available, then it will be used as the
- // touchable region so it won't cover the touchable letterbox and the touch
- // events can slip to activity from letterbox.
- mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+ if (Flags.scrollingFromLetterbox()) {
+ // Touchable region expands to the letterbox area to react to scrolls from letterbox.
+ mTmpRect.setEmpty();
+ } else {
+ // If the activity is letterboxed and scrolling from letterbox is disabled, limit the
+ // touchable region to the activity. This way, the letterbox area is exposed to react
+ // to touch events, and the touch events can slip from the activity from letterbox.
+ mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+ }
+
if (mTmpRect.isEmpty()) {
final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
if (transformedBounds != null) {
@@ -4409,6 +4415,17 @@
for (int i = mChildren.size() - 1; i >= 0; i--) {
committed |= mChildren.get(i).commitFinishDrawing(t);
}
+
+ // When a new activity is showing, update dim in this transaction
+ if (Flags.updateDimsWhenWindowShown()) {
+ final Dimmer dimmer = getDimController();
+ final WindowContainer<?> dimParent = getDimParent();
+ if (dimmer != null && dimParent != null) {
+ dimParent.adjustDims();
+ dimmer.updateDims(t);
+ }
+ }
+
// In case commitFinishDrawingLocked starts a window level animation, make sure the surface
// operation (reparent to leash) is synced with the visibility by transition.
if (getAnimationLeash() != null) {
@@ -5304,6 +5321,12 @@
super.prepareSurfaces();
}
+ @Override
+ void adjustDims() {
+ applyDims();
+ super.adjustDims();
+ }
+
void updateSurfacePositionIfNeeded() {
if (mWindowFrames.mRelFrame.top == mWindowFrames.mLastRelFrame.top
&& mWindowFrames.mRelFrame.left == mWindowFrames.mLastRelFrame.left) {
diff --git a/services/core/java/com/android/server/wm/WindowTracingDataSource.java b/services/core/java/com/android/server/wm/WindowTracingDataSource.java
index dc048ef..b92e525 100644
--- a/services/core/java/com/android/server/wm/WindowTracingDataSource.java
+++ b/services/core/java/com/android/server/wm/WindowTracingDataSource.java
@@ -38,8 +38,6 @@
public final class WindowTracingDataSource extends DataSource<WindowTracingDataSource.Instance,
WindowTracingDataSource.TlsState, Void> {
- public static final String DATA_SOURCE_NAME = "android.windowmanager";
-
public static class TlsState {
public final Config mConfig;
public final AtomicBoolean mIsStarting = new AtomicBoolean(true);
@@ -78,8 +76,8 @@
@NonNull
private final WeakReference<WindowTracingPerfetto> mWindowTracing;
- public WindowTracingDataSource(WindowTracingPerfetto windowTracing) {
- super(DATA_SOURCE_NAME);
+ public WindowTracingDataSource(WindowTracingPerfetto windowTracing, String dataSourceName) {
+ super(dataSourceName);
mWindowTracing = new WeakReference<>(windowTracing);
Producer.init(InitArguments.DEFAULTS);
diff --git a/services/core/java/com/android/server/wm/WindowTracingPerfetto.java b/services/core/java/com/android/server/wm/WindowTracingPerfetto.java
index 22d6c86..6e8094a 100644
--- a/services/core/java/com/android/server/wm/WindowTracingPerfetto.java
+++ b/services/core/java/com/android/server/wm/WindowTracingPerfetto.java
@@ -32,19 +32,21 @@
class WindowTracingPerfetto extends WindowTracing {
private static final String TAG = "WindowTracing";
+ private static final String PRODUCTION_DATA_SOURCE_NAME = "android.windowmanager";
private final AtomicInteger mCountSessionsOnFrame = new AtomicInteger();
private final AtomicInteger mCountSessionsOnTransaction = new AtomicInteger();
- private final WindowTracingDataSource mDataSource = new WindowTracingDataSource(this);
+ private final WindowTracingDataSource mDataSource;
WindowTracingPerfetto(WindowManagerService service, Choreographer choreographer) {
- this(service, choreographer, service.mGlobalLock);
+ this(service, choreographer, service.mGlobalLock, PRODUCTION_DATA_SOURCE_NAME);
}
@VisibleForTesting
WindowTracingPerfetto(WindowManagerService service, Choreographer choreographer,
- WindowManagerGlobalLock globalLock) {
+ WindowManagerGlobalLock globalLock, String dataSourceName) {
super(service, choreographer, globalLock);
+ mDataSource = new WindowTracingDataSource(this, dataSourceName);
}
@Override
diff --git a/services/core/jni/com_android_server_hint_HintManagerService.cpp b/services/core/jni/com_android_server_hint_HintManagerService.cpp
index 2307ace..febfb9f 100644
--- a/services/core/jni/com_android_server_hint_HintManagerService.cpp
+++ b/services/core/jni/com_android_server_hint_HintManagerService.cpp
@@ -109,7 +109,7 @@
return session_ptr;
} else if (result.isUnsupported()) {
throwUnsupported(env, result.errorMessage());
- return -1;
+ return 0;
}
throwFailed(env, result.errorMessage());
return 0;
@@ -190,7 +190,7 @@
hal::SessionConfig config;
jlong out = createHintSessionWithConfig(env, tgid, uid, std::move(threadIds), durationNanos,
sessionTag, config);
- if (out <= 0) {
+ if (out == 0) {
return out;
}
static jclass configClass = env->FindClass("android/hardware/power/SessionConfig");
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 75db316..b46a6ff 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -95,3 +95,10 @@
test_suites: ["device-tests"],
include_filters: ["com.android.server.pm.test.OverlayActorVisibilityTest"],
}
+
+test_module_config_host {
+ name: "PackageManagerServiceHostTests_android_server_pm_Presubmit",
+ base: "PackageManagerServiceHostTests",
+ test_suites: ["device-tests"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index 24e931c..f5b0015 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -186,3 +186,13 @@
include_filters: ["com.android.server.pm."],
include_annotations: ["android.platform.test.annotations.Postsubmit"],
}
+
+test_module_config {
+ name: "PackageManagerServiceServerTests_Presubmit",
+ base: "PackageManagerServiceServerTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/VpnTests/Android.bp b/services/tests/VpnTests/Android.bp
index ee20f1a..0568892 100644
--- a/services/tests/VpnTests/Android.bp
+++ b/services/tests/VpnTests/Android.bp
@@ -43,3 +43,10 @@
"android.test.mock.stubs",
],
}
+
+test_module_config {
+ name: "FrameworksVpnTests_android_server_connectivity",
+ base: "FrameworksVpnTests",
+ test_suites: ["device-tests"],
+ exclude_annotations: ["com.android.testutils.SkipPresubmit"],
+}
diff --git a/services/tests/appfunctions/Android.bp b/services/tests/appfunctions/Android.bp
index b5cf986..9560ec9 100644
--- a/services/tests/appfunctions/Android.bp
+++ b/services/tests/appfunctions/Android.bp
@@ -45,8 +45,8 @@
],
libs: [
- "android.test.base",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
certificate: "platform",
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
index 3ebf689..6930b3c 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
@@ -16,17 +16,28 @@
package com.android.server.appfunctions
import android.app.appfunctions.AppFunctionRuntimeMetadata
+import android.app.appsearch.AppSearchBatchResult
import android.app.appsearch.AppSearchManager
-import android.app.appsearch.AppSearchManager.SearchContext
+import android.app.appsearch.AppSearchResult
+import android.app.appsearch.AppSearchSchema
+import android.app.appsearch.GenericDocument
+import android.app.appsearch.GetByDocumentIdRequest
+import android.app.appsearch.GetSchemaResponse
import android.app.appsearch.PutDocumentsRequest
+import android.app.appsearch.RemoveByDocumentIdRequest
+import android.app.appsearch.SearchResult
+import android.app.appsearch.SearchSpec
import android.app.appsearch.SetSchemaRequest
+import android.app.appsearch.SetSchemaResponse
import android.util.ArrayMap
import android.util.ArraySet
+import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.infra.AndroidFuture
+import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors
-import org.junit.After
-import org.junit.Before
+import java.util.concurrent.atomic.AtomicBoolean
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -36,46 +47,21 @@
private val context = InstrumentationRegistry.getInstrumentation().targetContext
private val appSearchManager = context.getSystemService(AppSearchManager::class.java)
private val testExecutor = MoreExecutors.directExecutor()
-
- @Before
- @After
- fun clearData() {
- val searchContext = SearchContext.Builder(TEST_DB).build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaRequest = SetSchemaRequest.Builder().setForceOverride(true).build()
- it.setSchema(setSchemaRequest).get()
- }
- }
+ private val packageManager = context.packageManager
@Test
fun getPackageToFunctionIdMap() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+ val searchSession = FakeSearchSession()
val functionRuntimeMetadata =
AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
- val setSchemaRequest =
- SetSchemaRequest.Builder()
- .addSchemas(AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema())
- .addSchemas(
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(TEST_TARGET_PKG_NAME)
- )
- .build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaResponse = it.setSchema(setSchemaRequest).get()
- assertThat(setSchemaResponse).isNotNull()
- val appSearchBatchResult = it.put(putDocumentsRequest).get()
- assertThat(appSearchBatchResult.isSuccess).isTrue()
- }
+ searchSession.put(putDocumentsRequest).get()
- val metadataSyncAdapter =
- MetadataSyncAdapter(
- testExecutor,
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
- )
val packageToFunctionIdMap =
- metadataSyncAdapter.getPackageToFunctionIdMap(
- AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE,
+ MetadataSyncAdapter.getPackageToFunctionIdMap(
+ searchSession,
+ "fakeSchema",
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
)
@@ -86,7 +72,7 @@
@Test
fun getPackageToFunctionIdMap_multipleDocuments() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+ val searchSession = FakeSearchSession()
val functionRuntimeMetadata =
AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
val functionRuntimeMetadata1 =
@@ -95,13 +81,6 @@
AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId2", "").build()
val functionRuntimeMetadata3 =
AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId3", "").build()
- val setSchemaRequest =
- SetSchemaRequest.Builder()
- .addSchemas(AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema())
- .addSchemas(
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(TEST_TARGET_PKG_NAME)
- )
- .build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(
@@ -111,20 +90,11 @@
functionRuntimeMetadata3,
)
.build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaResponse = it.setSchema(setSchemaRequest).get()
- assertThat(setSchemaResponse).isNotNull()
- val appSearchBatchResult = it.put(putDocumentsRequest).get()
- assertThat(appSearchBatchResult.isSuccess).isTrue()
- }
+ searchSession.put(putDocumentsRequest).get()
- val metadataSyncAdapter =
- MetadataSyncAdapter(
- testExecutor,
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
- )
val packageToFunctionIdMap =
- metadataSyncAdapter.getPackageToFunctionIdMap(
+ MetadataSyncAdapter.getPackageToFunctionIdMap(
+ searchSession,
AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE,
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
@@ -159,6 +129,29 @@
}
@Test
+ fun syncMetadata_noDiff() {
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ runtimeSearchSession.put(putDocumentsRequest).get()
+ staticSearchSession.put(putDocumentsRequest).get()
+ val metadataSyncAdapter =
+ MetadataSyncAdapter(
+ testExecutor,
+ runtimeSearchSession,
+ staticSearchSession,
+ packageManager,
+ )
+
+ val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+
+ assertThat(submitSyncRequest.get()).isTrue()
+ }
+
+ @Test
fun getAddedFunctionsDiffMap_addedFunction() {
val staticPackageToFunctionMap: ArrayMap<String, ArraySet<String>> = ArrayMap()
staticPackageToFunctionMap.putAll(
@@ -180,6 +173,28 @@
}
@Test
+ fun syncMetadata_addedFunction() {
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ staticSearchSession.put(putDocumentsRequest).get()
+ val metadataSyncAdapter =
+ MetadataSyncAdapter(
+ testExecutor,
+ runtimeSearchSession,
+ staticSearchSession,
+ packageManager,
+ )
+
+ val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+
+ assertThat(submitSyncRequest.get()).isTrue()
+ }
+
+ @Test
fun getAddedFunctionsDiffMap_addedFunctionNewPackage() {
val staticPackageToFunctionMap: ArrayMap<String, ArraySet<String>> = ArrayMap()
staticPackageToFunctionMap.putAll(
@@ -215,6 +230,28 @@
}
@Test
+ fun syncMetadata_removedFunction() {
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ runtimeSearchSession.put(putDocumentsRequest).get()
+ val metadataSyncAdapter =
+ MetadataSyncAdapter(
+ testExecutor,
+ runtimeSearchSession,
+ staticSearchSession,
+ packageManager,
+ )
+
+ val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+
+ assertThat(submitSyncRequest.get()).isTrue()
+ }
+
+ @Test
fun getRemovedFunctionsDiffMap_noDiff() {
val staticPackageToFunctionMap: ArrayMap<String, ArraySet<String>> = ArrayMap()
staticPackageToFunctionMap.putAll(
@@ -271,4 +308,100 @@
const val TEST_DB: String = "test_db"
const val TEST_TARGET_PKG_NAME = "com.android.frameworks.appfunctionstests"
}
+
+ class FakeSearchSession : FutureAppSearchSession {
+ private val schemas: MutableSet<AppSearchSchema> = mutableSetOf()
+ private val genericDocumentMutableMap: MutableMap<String, GenericDocument> = mutableMapOf()
+
+ override fun close() {
+ Log.d("FakeRuntimeMetadataSearchSession", "Closing session")
+ }
+
+ override fun setSchema(
+ setSchemaRequest: SetSchemaRequest
+ ): AndroidFuture<SetSchemaResponse> {
+ schemas.addAll(setSchemaRequest.schemas)
+ return AndroidFuture.completedFuture(SetSchemaResponse.Builder().build())
+ }
+
+ override fun getSchema(): AndroidFuture<GetSchemaResponse> {
+ val resultBuilder = GetSchemaResponse.Builder()
+ for (schema in schemas) {
+ resultBuilder.addSchema(schema)
+ }
+ return AndroidFuture.completedFuture(resultBuilder.build())
+ }
+
+ override fun put(
+ putDocumentsRequest: PutDocumentsRequest
+ ): AndroidFuture<AppSearchBatchResult<String, Void>> {
+ for (document in putDocumentsRequest.genericDocuments) {
+ genericDocumentMutableMap[document.id] = document
+ }
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, Void>()
+ for (document in putDocumentsRequest.genericDocuments) {
+ batchResultBuilder.setResult(document.id, AppSearchResult.newSuccessfulResult(null))
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun remove(
+ removeRequest: RemoveByDocumentIdRequest
+ ): AndroidFuture<AppSearchBatchResult<String, Void>> {
+ for (documentId in removeRequest.ids) {
+ if (!genericDocumentMutableMap.keys.contains(documentId)) {
+ throw IllegalStateException("Document $documentId does not exist")
+ }
+ }
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, Void>()
+ for (id in removeRequest.ids) {
+ batchResultBuilder.setResult(id, AppSearchResult.newSuccessfulResult(null))
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun getByDocumentId(
+ getRequest: GetByDocumentIdRequest
+ ): AndroidFuture<AppSearchBatchResult<String, GenericDocument>> {
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, GenericDocument>()
+ for (documentId in getRequest.ids) {
+ if (!genericDocumentMutableMap.keys.contains(documentId)) {
+ throw IllegalStateException("Document $documentId does not exist")
+ }
+ batchResultBuilder.setResult(
+ documentId,
+ AppSearchResult.newSuccessfulResult(genericDocumentMutableMap[documentId]),
+ )
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun search(
+ queryExpression: String,
+ searchSpec: SearchSpec,
+ ): AndroidFuture<FutureSearchResults> {
+ val futureSearchResults =
+ object : FutureSearchResults {
+ val hasNextPage = AtomicBoolean(false)
+
+ override fun getNextPage(): AndroidFuture<MutableList<SearchResult>> {
+ val searchResultMutableList: MutableList<SearchResult> =
+ genericDocumentMutableMap.values
+ .map {
+ SearchResult.Builder(TEST_TARGET_PKG_NAME, TEST_DB)
+ .setGenericDocument(it)
+ .build()
+ }
+ .toMutableList()
+ if (!hasNextPage.get()) {
+ hasNextPage.set(true)
+ return AndroidFuture.completedFuture(searchResultMutableList)
+ } else {
+ return AndroidFuture.completedFuture(mutableListOf())
+ }
+ }
+ }
+ return AndroidFuture.completedFuture(futureSearchResults)
+ }
+ }
}
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index fe73025..36ea241 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -22,6 +22,7 @@
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "compatibility-device-util-axt",
"flag-junit",
"frameworks-base-testutils",
"junit",
@@ -48,6 +49,10 @@
"automotive-tests",
],
+ data: [
+ ":DisplayManagerTestApp",
+ ],
+
certificate: "platform",
dxflags: ["--multi-dex"],
diff --git a/services/tests/displayservicetests/AndroidManifest.xml b/services/tests/displayservicetests/AndroidManifest.xml
index 74260cd..37a34ee 100644
--- a/services/tests/displayservicetests/AndroidManifest.xml
+++ b/services/tests/displayservicetests/AndroidManifest.xml
@@ -39,6 +39,10 @@
android:testOnly="true">
<uses-library android:name="android.test.mock" android:required="true" />
<uses-library android:name="android.test.runner" />
+ <activity android:name="com.android.server.display.SimpleActivity"
+ android:exported="true" />
+ <activity android:name="com.android.server.display.SimpleActivity2"
+ android:exported="true" />
</application>
<instrumentation
diff --git a/services/tests/displayservicetests/AndroidTest.xml b/services/tests/displayservicetests/AndroidTest.xml
index 2985f98..f3697bb 100644
--- a/services/tests/displayservicetests/AndroidTest.xml
+++ b/services/tests/displayservicetests/AndroidTest.xml
@@ -23,6 +23,13 @@
<option name="test-file-name" value="DisplayServiceTests.apk" />
</target_preparer>
+ <!-- Load additional APKs onto device -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="DisplayManagerTestApp.apk" />
+ </target_preparer>
+
<option name="test-tag" value="DisplayServiceTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.displayservicetests" />
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java
new file mode 100644
index 0000000..90f6257
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2024 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.display;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.util.DisplayMetrics.DENSITY_HIGH;
+import static android.util.DisplayMetrics.DENSITY_MEDIUM;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.platform.test.annotations.AppModeSdkSandbox;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests that applications can receive display events correctly.
+ */
+@RunWith(Parameterized.class)
+@AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
+public class DisplayEventDeliveryTest {
+ private static final String TAG = "DisplayEventDeliveryTest";
+
+ private static final String NAME = TAG;
+ private static final int WIDTH = 720;
+ private static final int HEIGHT = 480;
+
+ private static final int MESSAGE_LAUNCHED = 1;
+ private static final int MESSAGE_CALLBACK = 2;
+
+ private static final int DISPLAY_ADDED = 1;
+ private static final int DISPLAY_CHANGED = 2;
+ private static final int DISPLAY_REMOVED = 3;
+
+ private static final long DISPLAY_EVENT_TIMEOUT_MSEC = 100;
+ private static final long TEST_FAILURE_TIMEOUT_MSEC = 10000;
+
+ private static final String TEST_PACKAGE =
+ "com.android.servicestests.apps.displaymanagertestapp";
+ private static final String TEST_ACTIVITY = TEST_PACKAGE + ".DisplayEventActivity";
+ private static final String TEST_DISPLAYS = "DISPLAYS";
+ private static final String TEST_MESSENGER = "MESSENGER";
+
+ private final Object mLock = new Object();
+
+ private Instrumentation mInstrumentation;
+ private Context mContext;
+ private DisplayManager mDisplayManager;
+ private ActivityManager mActivityManager;
+ private ActivityManager.OnUidImportanceListener mUidImportanceListener;
+ private CountDownLatch mLatchActivityLaunch;
+ private CountDownLatch mLatchActivityCached;
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private Messenger mMessenger;
+ private int mPid;
+ private int mUid;
+
+ /**
+ * Array of DisplayBundle. The test handler uses it to check if certain display events have
+ * been sent to DisplayEventActivity.
+ * Key: displayId of each new VirtualDisplay created by this test
+ * Value: DisplayBundle, storing the VirtualDisplay and its expected display events
+ *
+ * NOTE: The lock is required when adding and removing virtual displays. Otherwise it's not
+ * necessary to lock mDisplayBundles when accessing it from the test function.
+ */
+ @GuardedBy("mLock")
+ private SparseArray<DisplayBundle> mDisplayBundles;
+
+ /**
+ * Helper class to store VirtualDisplay and its corresponding display events expected to be
+ * sent to DisplayEventActivity.
+ */
+ private static final class DisplayBundle {
+ private VirtualDisplay mVirtualDisplay;
+ private final int mDisplayId;
+
+ // Display events we expect to receive before timeout
+ private final LinkedBlockingQueue<Integer> mExpectations;
+
+ DisplayBundle(VirtualDisplay display) {
+ mVirtualDisplay = display;
+ mDisplayId = display.getDisplay().getDisplayId();
+ mExpectations = new LinkedBlockingQueue<>();
+ }
+
+ public void releaseDisplay() {
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.release();
+ }
+ mVirtualDisplay = null;
+ }
+
+ /**
+ * Add the received display event from the test activity to the queue
+ *
+ * @param event The corresponding display event
+ */
+ public void addDisplayEvent(int event) {
+ Log.d(TAG, "Received " + mDisplayId + " " + event);
+ mExpectations.offer(event);
+ }
+
+
+ /**
+ * Assert that there isn't any unexpected display event from the test activity
+ */
+ public void assertNoDisplayEvents() {
+ try {
+ assertNull(mExpectations.poll(DISPLAY_EVENT_TIMEOUT_MSEC, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Wait for the expected display event from the test activity
+ *
+ * @param expect The expected display event
+ */
+ public void waitDisplayEvent(int expect) {
+ while (true) {
+ try {
+ final Integer event;
+ event = mExpectations.poll(TEST_FAILURE_TIMEOUT_MSEC, TimeUnit.MILLISECONDS);
+ assertNotNull(event);
+ if (expect == event) {
+ Log.d(TAG, "Found " + mDisplayId + " " + event);
+ return;
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * How many virtual displays to create during the test
+ */
+ @Parameter(0)
+ public int mDisplayCount;
+
+ /**
+ * True if running the test activity in cached mode
+ * False if running it in non-cached mode
+ */
+ @Parameter(1)
+ public boolean mCached;
+
+ @Parameters(name = "#{index}: {0} {1}")
+ public static Iterable<? extends Object> data() {
+ return Arrays.asList(new Object[][]{
+ {1, false}, {2, false}, {3, false}, {10, false},
+ {1, true}, {2, true}, {3, true}, {10, true}
+ });
+ }
+
+ private class TestHandler extends Handler {
+ TestHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ switch (msg.what) {
+ case MESSAGE_LAUNCHED:
+ mPid = msg.arg1;
+ mUid = msg.arg2;
+ Log.d(TAG, "Launched " + mPid + " " + mUid);
+ mLatchActivityLaunch.countDown();
+ break;
+ case MESSAGE_CALLBACK:
+ Log.d(TAG, "Callback " + msg.arg1 + " " + msg.arg2);
+ synchronized (mLock) {
+ // arg1: displayId
+ DisplayBundle bundle = mDisplayBundles.get(msg.arg1);
+ if (bundle != null) {
+ // arg2: display event
+ bundle.addDisplayEvent(msg.arg2);
+ }
+ }
+ break;
+ default:
+ fail("Unexpected value: " + msg.what);
+ break;
+ }
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = mInstrumentation.getContext();
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ mLatchActivityLaunch = new CountDownLatch(1);
+ mLatchActivityCached = new CountDownLatch(1);
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mUidImportanceListener = (uid, importance) -> {
+ if (uid == mUid && importance == IMPORTANCE_CACHED) {
+ Log.d(TAG, "Listener " + uid + " becomes " + importance);
+ mLatchActivityCached.countDown();
+ }
+ };
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ mActivityManager.addOnUidImportanceListener(mUidImportanceListener,
+ IMPORTANCE_CACHED));
+ // The lock is not functionally necessary but eliminates lint error messages.
+ synchronized (mLock) {
+ mDisplayBundles = new SparseArray<>();
+ }
+ mHandlerThread = new HandlerThread("handler");
+ mHandlerThread.start();
+ mHandler = new TestHandler(mHandlerThread.getLooper());
+ mMessenger = new Messenger(mHandler);
+ mPid = 0;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mActivityManager.removeOnUidImportanceListener(mUidImportanceListener);
+ mHandlerThread.quitSafely();
+ synchronized (mLock) {
+ for (int i = 0; i < mDisplayBundles.size(); i++) {
+ DisplayBundle bundle = mDisplayBundles.valueAt(i);
+ // Clean up unreleased virtual display
+ bundle.releaseDisplay();
+ }
+ mDisplayBundles.clear();
+ }
+ SystemUtil.runShellCommand(mInstrumentation, "am force-stop " + TEST_PACKAGE);
+ }
+
+ /**
+ * Return a display bundle at the stated index. The bundle is retrieved under lock.
+ */
+ private DisplayBundle displayBundleAt(int i) {
+ synchronized (mLock) {
+ return mDisplayBundles.valueAt(i);
+ }
+ }
+
+ /**
+ * Create virtual displays, change their configurations and release them
+ * mDisplays: the amount of virtual displays to be created
+ * mCached: true to run the test activity in cached mode; false in non-cached mode
+ */
+ @Test
+ public void testDisplayEvents() {
+ Log.d(TAG, "Start test testDisplayEvents " + mDisplayCount + " " + mCached);
+ // Launch DisplayEventActivity and start listening to display events
+ launchTestActivity();
+
+ if (mCached) {
+ // The test activity in cached mode won't receive the pending display events
+ makeTestActivityCached();
+ }
+
+ // Create new virtual displays
+ for (int i = 0; i < mDisplayCount; i++) {
+ // Lock is needed here to ensure the handler can query the displays
+ synchronized (mLock) {
+ VirtualDisplay display = createVirtualDisplay(NAME + i);
+ DisplayBundle bundle = new DisplayBundle(display);
+ mDisplayBundles.put(bundle.mDisplayId, bundle);
+ }
+ }
+
+ for (int i = 0; i < mDisplayCount; i++) {
+ if (mCached) {
+ // DISPLAY_ADDED should be deferred for cached process
+ displayBundleAt(i).assertNoDisplayEvents();
+ } else {
+ // DISPLAY_ADDED should arrive immediately for non-cached process
+ displayBundleAt(i).waitDisplayEvent(DISPLAY_ADDED);
+ }
+ }
+
+ // Change the virtual displays
+ for (int i = 0; i < mDisplayCount; i++) {
+ DisplayBundle bundle = displayBundleAt(i);
+ bundle.mVirtualDisplay.resize(WIDTH, HEIGHT, DENSITY_HIGH);
+ }
+
+ for (int i = 0; i < mDisplayCount; i++) {
+ if (mCached) {
+ // DISPLAY_CHANGED should be deferred for cached process
+ displayBundleAt(i).assertNoDisplayEvents();
+ } else {
+ // DISPLAY_CHANGED should arrive immediately for non-cached process
+ displayBundleAt(i).waitDisplayEvent(DISPLAY_CHANGED);
+ }
+ }
+
+ if (mCached) {
+ // The test activity becomes non-cached and should receive the pending display events
+ bringTestActivityTop();
+
+ for (int i = 0; i < mDisplayCount; i++) {
+ // The pending DISPLAY_ADDED & DISPLAY_CHANGED should arrive now
+ displayBundleAt(i).waitDisplayEvent(DISPLAY_ADDED);
+ displayBundleAt(i).waitDisplayEvent(DISPLAY_CHANGED);
+ }
+ }
+
+ // Release the virtual displays
+ for (int i = 0; i < mDisplayCount; i++) {
+ displayBundleAt(i).releaseDisplay();
+ }
+
+ // DISPLAY_REMOVED should arrive now
+ for (int i = 0; i < mDisplayCount; i++) {
+ displayBundleAt(i).waitDisplayEvent(DISPLAY_REMOVED);
+ }
+ }
+
+ /**
+ * Launch the test activity that would listen to display events
+ */
+ private void launchTestActivity() {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName(TEST_PACKAGE, TEST_ACTIVITY);
+ intent.putExtra(TEST_MESSENGER, mMessenger);
+ intent.putExtra(TEST_DISPLAYS, mDisplayCount);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> {
+ mContext.startActivity(intent);
+ },
+ android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
+ waitLatch(mLatchActivityLaunch);
+ }
+
+ /**
+ * Bring the test activity back to top
+ */
+ private void bringTestActivityTop() {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName(TEST_PACKAGE, TEST_ACTIVITY);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> {
+ mContext.startActivity(intent);
+ },
+ android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
+ }
+
+ /**
+ * Bring the test activity into cached mode by launching another 2 apps
+ */
+ private void makeTestActivityCached() {
+ // Launch another activity to bring the test activity into background
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(mContext, SimpleActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+
+ // Launch another activity to bring the test activity into cached mode
+ Intent intent2 = new Intent(Intent.ACTION_MAIN);
+ intent2.setClass(mContext, SimpleActivity2.class);
+ intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> {
+ mInstrumentation.startActivitySync(intent);
+ mInstrumentation.startActivitySync(intent2);
+ },
+ android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
+ waitLatch(mLatchActivityCached);
+ }
+
+ /**
+ * Create a virtual display
+ *
+ * @param name The name of the new virtual display
+ * @return The new virtual display
+ */
+ private VirtualDisplay createVirtualDisplay(String name) {
+ return mDisplayManager.createVirtualDisplay(name, WIDTH, HEIGHT, DENSITY_MEDIUM,
+ null /* surface: as we don't actually draw anything, null is enough */,
+ VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ /* flags: a public virtual display that another app can access */);
+ }
+
+ /**
+ * Wait for CountDownLatch with timeout
+ */
+ private void waitLatch(CountDownLatch latch) {
+ try {
+ latch.await(TEST_FAILURE_TIMEOUT_MSEC, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 76c8e686..8b80f85 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -117,6 +117,7 @@
import android.provider.Settings.SettingNotFoundException;
import android.test.mock.MockContentResolver;
import android.util.SparseArray;
+import android.util.Spline;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.DisplayAdjustments;
@@ -141,6 +142,7 @@
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.display.DisplayManagerService.DeviceStateListener;
import com.android.server.display.DisplayManagerService.SyncRoot;
+import com.android.server.display.config.HdrBrightnessData;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.Layout;
@@ -3203,6 +3205,45 @@
}
@Test
+ public void testHighestHdrSdrRatio() {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+ displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ float highestRatio = 9.5f;
+ HdrBrightnessData hdrData = new HdrBrightnessData(Collections.emptyMap(),
+ /* brightnessIncreaseDebounceMillis= */ 0, /* screenBrightnessRampIncrease= */ 0,
+ /* brightnessDecreaseDebounceMillis= */ 0, /* screenBrightnessRampDecrease= */ 0,
+ /* hbmTransitionPoint= */ 0, /* minimumHdrPercentOfScreenForNbm= */ 0,
+ /* minimumHdrPercentOfScreenForHbm= */ 0, /* allowInLowPowerMode= */ false,
+ mock(Spline.class), highestRatio);
+ when(mMockDisplayDeviceConfig.getHdrBrightnessData()).thenReturn(hdrData);
+
+ assertEquals(highestRatio, displayManagerBinderService.getHighestHdrSdrRatio(displayId),
+ /* delta= */ 0);
+ }
+
+ @Test
+ public void testHighestHdrSdrRatio_HdrDataNull() {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+ displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+ when(mMockDisplayDeviceConfig.getHdrBrightnessData()).thenReturn(null);
+
+ assertEquals(1, displayManagerBinderService.getHighestHdrSdrRatio(displayId),
+ /* delta= */ 0);
+ }
+
+ @Test
public void testOnDisplayChanged_HbmMetadataNull() {
DisplayPowerController dpc = mock(DisplayPowerController.class);
DisplayManagerService.Injector injector = new BasicInjector() {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index d0aec3b..bf5a692 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -75,6 +75,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.app.IBatteryStats;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
@@ -158,6 +159,8 @@
private DisplayManagerFlags mDisplayManagerFlagsMock;
@Mock
private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession;
+ @Mock
+ private IBatteryStats mMockBatteryStats;
@Captor
private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;
@@ -204,7 +207,8 @@
doAnswer((Answer<Void>) invocationOnMock -> null).when(() ->
SystemProperties.set(anyString(), any()));
- doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService);
+ doAnswer((Answer<IBatteryStats>) invocationOnMock -> mMockBatteryStats)
+ .when(BatteryStatsService::getService);
doAnswer((Answer<Boolean>) invocationOnMock -> false)
.when(ActivityManager::isLowRamDeviceStatic);
@@ -2227,6 +2231,52 @@
verify(mHolder.brightnessSetting).saveIfNeeded();
}
+ @Test
+ public void testBatteryStatNotes_enabledOnDefaultDisplayWhenDisabledOnOthers()
+ throws Exception {
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
+
+ verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+ }
+
+ @Test
+ public void testBatteryStatNotes_enabledOnDefaultDisplayWhenEnabledOnOthers() throws Exception {
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
+
+ verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+ }
+
+ @Test
+ public void testBatteryStatNotes_flagGuardedOnNonDefaultDisplays() throws Exception {
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
+
+ verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ false);
+
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
+
+ verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ true);
+ }
+
+ private void verifyNoteScreenState(int displayId, boolean expectNote) throws Exception {
+ mHolder = createDisplayPowerController(displayId, UNIQUE_ID);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ if (expectNote) {
+ verify(mMockBatteryStats)
+ .noteScreenState(
+ displayId, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY);
+ verify(mMockBatteryStats).noteScreenBrightness(eq(displayId), anyInt());
+ } else {
+ verify(mMockBatteryStats, never()).noteScreenState(anyInt(), anyInt(), anyInt());
+ verify(mMockBatteryStats, never()).noteScreenBrightness(anyInt(), anyInt());
+ }
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java
similarity index 69%
copy from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
copy to services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java
index 48ec198..c4ebbd9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.scene.ui.composable.transitions
+package com.android.server.display;
-import com.android.compose.animation.scene.TransitionBuilder
+import android.app.Activity;
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
-}
+/**
+ * An activity doing nothing
+ */
+public final class SimpleActivity extends Activity { }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java
similarity index 69%
copy from packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
copy to services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java
index 48ec198..a719a57 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.scene.ui.composable.transitions
+package com.android.server.display;
-import com.android.compose.animation.scene.TransitionBuilder
+import android.app.Activity;
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
-}
+/**
+ * Another activity doing nothing
+ */
+public final class SimpleActivity2 extends Activity { }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
index c758033..0db7de4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
@@ -61,7 +61,8 @@
minimumHdrPercentOfScreenForNbm: Float = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
minimumHdrPercentOfScreenForHbm: Float = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
allowInLowPowerMode: Boolean = false,
- sdrToHdrRatioSpline: Spline? = null
+ sdrToHdrRatioSpline: Spline? = null,
+ highestHdrSdrRatio: Float = 1f
): HdrBrightnessData {
return HdrBrightnessData(
maxBrightnessLimits,
@@ -73,7 +74,8 @@
minimumHdrPercentOfScreenForNbm,
minimumHdrPercentOfScreenForHbm,
allowInLowPowerMode,
- sdrToHdrRatioSpline
+ sdrToHdrRatioSpline,
+ highestHdrSdrRatio
)
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt b/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
index 917c681..48920d8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
@@ -28,7 +28,7 @@
class HdrBrightnessDataTest {
@Test
- fun `test HdrBrightnessData default configuration`() {
+ fun testHdrBrightnessData_defaultConfiguration() {
val displayConfiguration = createDisplayConfiguration {
hdrBrightnessConfig(
brightnessDecreaseDebounceMillis = "3000",
@@ -64,10 +64,11 @@
)
assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
assertThat(hdrBrightnessData.sdrToHdrRatioSpline).isNull()
+ assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(1)
}
@Test
- fun `test HdrBrightnessData fallback configuration`() {
+ fun testHdrBrightnessData_fallbackConfiguration() {
val displayConfiguration = createDisplayConfiguration {
hdrBrightnessConfig(
minimumHdrPercentOfScreenForNbm = null,
@@ -77,7 +78,7 @@
)
highBrightnessMode(
minimumHdrPercentOfScreen = "0.2",
- sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+ sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "7.0"))
)
}
@@ -91,17 +92,18 @@
assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.2f)
assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
- val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 8.0f))
+ val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 7.0f))
assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
.isEqualTo(expectedSpline.toString())
+ assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(7)
}
@Test
- fun `test HdrBrightnessData fallback configuration no hdrBrightnessConfig`() {
+ fun testHdrBrightnessData_fallbackConfiguration_noHdrBrightnessConfig() {
val displayConfiguration = createDisplayConfiguration {
highBrightnessMode(
minimumHdrPercentOfScreen = "0.2",
- sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+ sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "7.0"))
)
}
@@ -124,13 +126,14 @@
assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.2f)
assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
- val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 8.0f))
+ val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 7.0f))
assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
.isEqualTo(expectedSpline.toString())
+ assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(7)
}
@Test
- fun `test HdrBrightnessData configuration no configuration`() {
+ fun testHdrBrightnessData_emptyConfiguration() {
val displayConfiguration = createDisplayConfiguration()
val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration) { 0.6f }
@@ -138,17 +141,17 @@
}
@Test
- fun `test HdrBrightnessData real configuration`() {
+ fun testHdrBrightnessData_realConfiguration() {
val displayConfiguration = createDisplayConfiguration {
hdrBrightnessConfig(
minimumHdrPercentOfScreenForNbm = "0.3",
minimumHdrPercentOfScreenForHbm = "0.6",
allowInLowPowerMode = "true",
- sdrHdrRatioMap = listOf(Pair("3.0", "5.0"), Pair("6.0", "8.0"))
+ sdrHdrRatioMap = listOf(Pair("3.0", "5.0"), Pair("6.0", "7.0"))
)
highBrightnessMode(
minimumHdrPercentOfScreen = "0.2",
- sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+ sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "7.5"))
)
}
@@ -162,8 +165,9 @@
assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.6f)
assertThat(hdrBrightnessData.allowInLowPowerMode).isTrue()
- val expectedSpline = createSpline(floatArrayOf(3.0f, 6.0f), floatArrayOf(5.0f, 8.0f))
+ val expectedSpline = createSpline(floatArrayOf(3.0f, 6.0f), floatArrayOf(5.0f, 7.0f))
assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
.isEqualTo(expectedSpline.toString())
+ assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(7)
}
}
\ No newline at end of file
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 1abc557..1128f52 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -39,7 +39,6 @@
import android.view.WindowManager;
import androidx.annotation.NonNull;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -106,6 +105,12 @@
mMonitor.onEndDream();
super.onEndDream();
}
+
+ @Override
+ public void onWakeUp() {
+ mMonitor.onWakeUp();
+ super.onWakeUp();
+ }
}
/**
@@ -128,7 +133,6 @@
* Verifies that callbacks for subclasses are run on the provided executor.
*/
@Test
- @FlakyTest(bugId = 293108088)
public void testCallbacksRunOnExecutor() throws RemoteException {
final TestDreamOverlayService.Monitor monitor = Mockito.mock(
TestDreamOverlayService.Monitor.class);
@@ -153,6 +157,8 @@
// Callback is run.
verify(monitor).onStartDream();
+ clearInvocations(mExecutor);
+
// Verify onWakeUp is run on the executor.
client.wakeUp();
verify(monitor, never()).onWakeUp();
@@ -161,6 +167,8 @@
mRunnableCaptor.getValue().run();
verify(monitor).onWakeUp();
+ clearInvocations(mExecutor);
+
// Verify onEndDream is run on the executor.
client.endDream();
verify(monitor, never()).onEndDream();
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 6fc80b8..c81d6be 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -391,3 +391,13 @@
],
include_filters: ["com.android.server.trust"],
}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_storagemanagerservicetest",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.StorageManagerServiceTest"],
+}
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus
new file mode 100644
index 0000000..8b0fab8
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus
@@ -0,0 +1 @@
+0-1
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus
new file mode 100644
index 0000000..40c7bb2
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus
@@ -0,0 +1 @@
+0-3
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
index 2fbe8aa..3fe038a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.res.AssetManager;
+import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
@@ -48,6 +49,7 @@
private static final String TAG = CpuInfoReaderTest.class.getSimpleName();
private static final String ROOT_DIR_NAME = "CpuInfoReaderTest";
private static final String VALID_CPUSET_DIR = "valid_cpuset";
+ private static final String VALID_CPUSET_2_DIR = "valid_cpuset_2";
private static final String VALID_CPUSET_WITH_EMPTY_CPUS = "valid_cpuset_with_empty_cpus";
private static final String VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS =
"valid_cpufreq_with_empty_affected_cpus";
@@ -88,54 +90,95 @@
}
@Test
+ public void testReadCpuInfoWithUpdatedCpuset() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithUpdatedCpusetBeforeStopSignal() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ // When stopping the periodic cpuset reading, the reader will create a new snapshot.
+ cpuInfoReader.stopPeriodicCpusetReading();
+ // Any cpuset update after the stop signal should be ignored by the reader.
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+
+ @Test
+ public void testReadCpuInfoWithUpdatedCpusetAfterStopSignal() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.stopPeriodicCpusetReading();
+ // Any cpuset update after the stop signal should be ignored by the reader.
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot();
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
public void testReadCpuInfoWithTimeInState() throws Exception {
CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
- SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
- expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
- /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
- /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
- /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
- /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
- /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
- /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
- /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
- /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
- /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
- /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
- /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
- /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
- /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
- /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
- /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
- /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
- /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
- /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
- /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
- /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
- /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
- /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
@@ -144,49 +187,7 @@
actualCpuInfos = cpuInfoReader.readCpuInfos();
- expectedCpuInfos.clear();
- expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
- /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
- /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
- /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000,
- /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
- /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
- /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
- /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
- /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
- /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
- /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
- /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
- /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
- /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
- /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
- /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY,
- /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
- /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
- /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
- /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
- /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot();
compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
}
@@ -592,4 +593,108 @@
}
return rootDir.delete();
}
+
+ private SparseArray<CpuInfoReader.CpuInfo> getFirstCpuInfosWithTimeInStateSnapshot() {
+ SparseArray<CpuInfoReader.CpuInfo> cpuInfos = new SparseArray<>();
+ cpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
+ /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
+ /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
+ /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
+ /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
+ /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
+ /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
+ /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+ /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
+ /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
+ /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
+ /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
+ /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
+ /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
+ /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
+ /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
+ /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
+ /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
+ /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
+ /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
+ /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ return cpuInfos;
+ }
+
+ private SparseArray<CpuInfoReader.CpuInfo> getSecondCpuInfosWithTimeInStateSnapshot() {
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ return getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+ }
+
+ private SparseArray<CpuInfoReader.CpuInfo> getSecondCpuInfosWithTimeInStateSnapshot(
+ IntArray cpusetCategories) {
+ SparseArray<CpuInfoReader.CpuInfo> cpuInfos = new SparseArray<>();
+ cpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, cpusetCategories.get(0),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
+ /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
+ /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
+ /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000,
+ /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, cpusetCategories.get(1),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
+ /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
+ /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
+ /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
+ /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
+ /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, cpusetCategories.get(2),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
+ /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
+ /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
+ /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
+ /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
+ /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
+ /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, cpusetCategories.get(3),
+ /* isOnline= */ false,
+ /* curCpuFreqKHz= */ MISSING_FREQUENCY, /* maxCpuFreqKHz= */ 2_100_000,
+ /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+ /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
+ /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
+ /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
+ /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ return cpuInfos;
+ }
+
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
index 994313f..d9e09d8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
@@ -26,6 +26,7 @@
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
import static com.android.server.cpu.CpuMonitorService.DEFAULT_MONITORING_INTERVAL_MILLISECONDS;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -75,6 +76,7 @@
private static final long TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS = 100;
private static final long TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS = 150;
private static final long TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS = 300;
+ private static final long TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS = 0;
private static final CpuAvailabilityMonitoringConfig TEST_MONITORING_CONFIG_ALL_CPUSET =
new CpuAvailabilityMonitoringConfig.Builder(CPUSET_ALL)
.addThreshold(30).addThreshold(70).build();
@@ -119,7 +121,8 @@
mService = new CpuMonitorService(mMockContext, mMockCpuInfoReader, mServiceHandlerThread,
/* shouldDebugMonitor= */ true, TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS,
TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS,
- TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
doNothing().when(() -> ServiceManager.addService(eq("cpu_monitor"), any(Binder.class),
anyBoolean(), anyInt()));
@@ -535,6 +538,18 @@
}
@Test
+ public void testBootCompleted() throws Exception {
+ mService.onBootPhase(PHASE_BOOT_COMPLETED);
+
+ // Message to stop periodic cpuset reading is posted on the service handler thread. Sync
+ // with this thread before proceeding.
+ syncWithHandler(mServiceHandler, /* delayMillis= */ 0);
+
+ verify(mMockCpuInfoReader, timeout(ASYNC_CALLBACK_WAIT_TIMEOUT_MILLISECONDS))
+ .stopPeriodicCpusetReading();
+ }
+
+ @Test
public void testHeavyCpuLoadMonitoring() throws Exception {
// TODO(b/267500110): Once heavy CPU load detection logic is added, add unittest.
}
@@ -567,7 +582,8 @@
mServiceHandlerThread, /* shouldDebugMonitor= */ false,
TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS,
TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS,
- TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
startService();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
index 127d3e8..7ac7aca 100644
--- a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
@@ -39,9 +39,9 @@
],
libs: [
- "android.test.mock",
- "android.test.base",
- "android.test.runner",
+ "android.test.mock.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
jni_libs: [
diff --git a/services/tests/ondeviceintelligencetests/Android.bp b/services/tests/ondeviceintelligencetests/Android.bp
index aa85942..a31a3fb 100644
--- a/services/tests/ondeviceintelligencetests/Android.bp
+++ b/services/tests/ondeviceintelligencetests/Android.bp
@@ -47,9 +47,9 @@
],
libs: [
- "android.test.mock",
- "android.test.base",
- "android.test.runner",
+ "android.test.mock.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
certificate: "platform",
diff --git a/services/tests/performancehinttests/Android.bp b/services/tests/performancehinttests/Android.bp
index 1692921c..c8121fc 100644
--- a/services/tests/performancehinttests/Android.bp
+++ b/services/tests/performancehinttests/Android.bp
@@ -19,7 +19,7 @@
"truth",
],
libs: [
- "android.test.base",
+ "android.test.base.stubs.system",
],
test_suites: [
"automotive-tests",
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index b2ca991..639ae30 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -48,7 +48,9 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.hardware.common.fmq.MQDescriptor;
import android.hardware.power.ChannelConfig;
+import android.hardware.power.ChannelMessage;
import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
@@ -167,6 +169,8 @@
mConfig = new ChannelConfig();
mConfig.readFlagBitmask = 1;
mConfig.writeFlagBitmask = 2;
+ mConfig.channelDescriptor = new MQDescriptor<ChannelMessage, Byte>();
+ mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>();
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
index f74cfae..c0be865 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
@@ -56,14 +56,14 @@
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{300_000_000},
new int[]{Display.STATE_ON}, 0);
- stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_DOZE, Display.STATE_REASON_DEFAULT_POLICY,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{200_000_000},
new int[]{Display.STATE_DOZE}, 30 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_DEFAULT_POLICY,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{100_000_000},
new int[]{Display.STATE_OFF}, 120 * MINUTE_IN_MS);
@@ -93,37 +93,37 @@
final int[] screenStates = new int[] {Display.STATE_OFF, Display.STATE_OFF};
- stats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0);
- stats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0);
+ stats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN, 0, 0, 0);
+ stats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN, 0, 0, 0);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{300, 400}, screenStates, 0);
// Switch display0 to doze
screenStates[0] = Display.STATE_DOZE;
- stats.noteScreenStateLocked(0, screenStates[0], 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{200, 300},
screenStates, 30 * MINUTE_IN_MS);
// Switch display1 to doze
screenStates[1] = Display.STATE_DOZE;
- stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS,
- 90 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS);
// 100,000,000 uC should be attributed to display 0 doze here.
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{100_000_000, 700_000_000},
screenStates, 90 * MINUTE_IN_MS);
// Switch display0 to off
screenStates[0] = Display.STATE_OFF;
- stats.noteScreenStateLocked(0, screenStates[0], 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
// 40,000,000 and 70,000,000 uC should be attributed to display 0 and 1 doze here.
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{40_000_000, 70_000_000},
screenStates, 120 * MINUTE_IN_MS);
// Switch display1 to off
screenStates[1] = Display.STATE_OFF;
- stats.noteScreenStateLocked(1, screenStates[1], 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS,
- 150 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{100, 90_000_000}, screenStates,
150 * MINUTE_IN_MS);
// 90,000,000 uC should be attributed to display 1 doze here.
@@ -148,10 +148,10 @@
public void testPowerProfileBasedModel() {
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
- stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
AmbientDisplayPowerCalculator calculator =
new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
@@ -174,15 +174,15 @@
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
- stats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0);
- stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS,
- 90 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(1, Display.STATE_OFF, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS,
- 150 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN, 0, 0, 0);
+ stats.noteScreenStateLocked(0, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS);
AmbientDisplayPowerCalculator calculator =
new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
index afbe9159..2ccb642 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
@@ -44,6 +44,10 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;
import android.telephony.AccessNetworkConstants;
import android.telephony.ActivityStatsTechSpecificInfo;
@@ -65,6 +69,7 @@
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
import com.android.internal.power.EnergyConsumerStats;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.BatteryStatsImpl.DualTimer;
import org.junit.Rule;
@@ -90,6 +95,8 @@
.setProvideMainThread(true)
.build();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final String TAG = BatteryStatsNoteTest.class.getSimpleName();
private static final int UID = 10500;
@@ -104,6 +111,54 @@
@Mock
NetworkStatsManager mNetworkStatsManager;
+ @DisabledOnRavenwood
+ @EnableFlags(Flags.FLAG_BATTERY_STATS_SCREEN_STATE_EVENT)
+ @Test
+ public void testScreenStateEvent_screenStateEventFlagOn_eventsRecorded() throws Exception {
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClock());
+ bi.forceRecordAllHistory();
+
+ bi.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY,
+ 0, 0, 0);
+ bi.noteScreenStateLocked(2, Display.STATE_DOZE_SUSPEND, Display.STATE_REASON_DRAW_WAKE_LOCK,
+ 1, 1, 1);
+
+ BatteryStatsHistoryIterator iterator =
+ bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
+ BatteryStats.HistoryItem item =
+ iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED);
+ assertThat(item).isNotNull();
+ assertThat(item.eventTag).isNotNull();
+ assertThat(item.eventTag.string).isEqualTo("display=0 state=ON reason=DEFAULT_POLICY");
+ assertThat(item.eventTag.uid).isEqualTo(Process.INVALID_UID);
+
+ item = iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED);
+ assertThat(item).isNotNull();
+ assertThat(item.eventTag).isNotNull();
+ assertThat(item.eventTag.string)
+ .isEqualTo("display=2 state=DOZE_SUSPEND reason=DRAW_WAKE_LOCK");
+ assertThat(item.eventTag.uid).isEqualTo(Process.INVALID_UID);
+
+ // Last check to make sure that we did not record any extra event.
+ assertThat(iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED)).isNull();
+ }
+
+ @DisableFlags(Flags.FLAG_BATTERY_STATS_SCREEN_STATE_EVENT)
+ @Test
+ public void testScreenStateEvent_screenStateEventFlagOff_eventsNotRecorded() throws Exception {
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClock());
+ bi.forceRecordAllHistory();
+
+ bi.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY,
+ 0, 0, 0);
+ bi.noteScreenStateLocked(2, Display.STATE_DOZE_SUSPEND, Display.STATE_REASON_DRAW_WAKE_LOCK,
+ 1, 1, 1);
+
+ BatteryStatsHistoryIterator iterator =
+ bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
+ assertThat(iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED)).isNull();
+ }
+
/**
* Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
*/
@@ -285,20 +340,15 @@
final BatteryStatsHistoryIterator iterator =
bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
- BatteryStats.HistoryItem item;
+ BatteryStats.HistoryItem item =
+ iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_START);
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_START) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+ assertThat(item).isNotNull();
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+ item = iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
@@ -343,20 +393,15 @@
final BatteryStatsHistoryIterator iterator =
bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
- BatteryStats.HistoryItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_START) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+ BatteryStats.HistoryItem item =
+ iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+ assertThat(item).isNotNull();
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+ item = iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+ assertThat(item).isNotNull();
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
@@ -2562,4 +2607,18 @@
currentTimeMs, currentTimeMs, mNetworkStatsManager);
}
}
+
+ /**
+ * Moves a given {@link BatteryStatsHistoryIterator} until a history item with the given
+ * {@code eventCode} is found and returns the history item. Returns {@code null} if no such item
+ * is found.
+ */
+ private static BatteryStats.HistoryItem iterateAndFind(
+ BatteryStatsHistoryIterator iterator, int eventCode) {
+ BatteryStats.HistoryItem item;
+ while ((item = iterator.next()) != null) {
+ if (item.eventCode == eventCode) return item;
+ }
+ return null;
+ }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
index e4ab227..38fc6a9 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
@@ -39,11 +39,11 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.PowerManager;
import android.os.Process;
import android.os.SystemClock;
import android.platform.test.ravenwood.RavenwoodRule;
@@ -52,10 +52,10 @@
import android.util.DebugUtils;
import android.util.KeyValueListParser;
import android.util.Log;
+import android.view.Display;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
import com.android.frameworks.coretests.aidl.ICmdCallback;
@@ -66,7 +66,6 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
@@ -103,6 +102,7 @@
private static final int GENERAL_TIMEOUT_MS = 4000;
private static final int GENERAL_INTERVAL_MS = 200;
+ private static final int SCREEN_STATE_CHANGE_TIMEOUT_MS = 10000;
private static final int WORK_DURATION_MS = 2000;
@@ -110,6 +110,7 @@
private static String sOriginalBatteryStatsConsts;
private static Context sContext;
+ private static Display sDisplay;
private static UiDevice sUiDevice;
private static int sTestPkgUid;
private static boolean sCpuFreqTimesAvailable;
@@ -131,6 +132,10 @@
sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0);
executeCmd("cmd deviceidle whitelist +" + TEST_PKG);
checkCpuTimesAvailability();
+ DisplayManager displayManager = sContext.getSystemService(DisplayManager.class);
+ if (displayManager != null) {
+ sDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ }
}
@AfterClass
@@ -833,12 +838,12 @@
executeCmd("input keyevent KEYCODE_WAKEUP");
executeCmd("wm dismiss-keyguard");
assertKeyguardUnLocked();
- assertScreenInteractive(true);
+ assertScreenState(true);
}
private void screenoff() throws Exception {
executeCmd("input keyevent KEYCODE_SLEEP");
- assertScreenInteractive(false);
+ assertScreenState(false);
}
private void forceStop() throws Exception {
@@ -854,12 +859,15 @@
);
}
- private void assertScreenInteractive(boolean interactive) throws Exception {
- final PowerManager powerManager =
- (PowerManager) sContext.getSystemService(Context.POWER_SERVICE);
- assertDelayedCondition("Unexpected screen interactive state", () ->
- interactive == powerManager.isInteractive() ? null : "expected=" + interactive
- );
+ private void assertScreenState(boolean expectedOn) throws Exception {
+ if (sDisplay == null) {
+ return;
+ }
+
+ assertDelayedCondition("Unexpected screen-on state",
+ () -> expectedOn == Display.isOnState(sDisplay.getState())
+ ? null : "expected=" + expectedOn,
+ SCREEN_STATE_CHANGE_TIMEOUT_MS, GENERAL_INTERVAL_MS);
}
private void assertDelayedCondition(String errMsgPrefix, ExpectedCondition condition)
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
index 88d4ea7..2da98e8 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
@@ -61,7 +61,8 @@
mStatsRule.initMeasuredEnergyStatsLocked();
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{0},
new int[]{Display.STATE_ON}, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
@@ -79,7 +80,7 @@
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{300_000_000},
new int[]{Display.STATE_ON}, 60 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
+ batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
@@ -150,8 +151,10 @@
final int[] screenStates = new int[]{Display.STATE_ON, Display.STATE_OFF};
- batteryStats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0);
- batteryStats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
+ batteryStats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, 0, 0);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{300, 400}, screenStates, 0);
@@ -166,10 +169,10 @@
screenStates[0] = Display.STATE_OFF;
screenStates[1] = Display.STATE_ON;
- batteryStats.noteScreenStateLocked(0, screenStates[0],
+ batteryStats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(1, screenStates[1], 80 * MINUTE_IN_MS,
- 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{600_000_000, 500},
screenStates, 80 * MINUTE_IN_MS);
@@ -178,8 +181,8 @@
batteryStats.noteScreenBrightnessLocked(1, 75, 98 * MINUTE_IN_MS, 98 * MINUTE_IN_MS);
screenStates[1] = Display.STATE_OFF;
- batteryStats.noteScreenStateLocked(1, screenStates[1], 110 * MINUTE_IN_MS,
- 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{700, 800_000_000},
screenStates, 110 * MINUTE_IN_MS);
@@ -240,7 +243,8 @@
public void testPowerProfileBasedModel() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
0, 0);
@@ -253,7 +257,7 @@
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
+ batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
@@ -313,8 +317,10 @@
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
- batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
+ batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
0, 0);
@@ -327,16 +333,16 @@
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
+ batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(1, Display.STATE_ON, 80 * MINUTE_IN_MS,
- 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(1, 20, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(1, 250, 86 * MINUTE_IN_MS, 86 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(1, 75, 98 * MINUTE_IN_MS, 98 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, 110 * MINUTE_IN_MS,
- 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
diff --git a/services/tests/selinux/Android.bp b/services/tests/selinux/Android.bp
index 12a7038..048978a 100644
--- a/services/tests/selinux/Android.bp
+++ b/services/tests/selinux/Android.bp
@@ -42,9 +42,9 @@
"mockito_extended",
],
libs: [
- "android.test.base",
- "android.test.mock",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
+ "android.test.runner.stubs.system",
"servicestests-core-utils",
],
static_libs: [
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 895cd1e..bbe0755 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -30,6 +30,7 @@
"src/**/*.kt",
"test-apps/SuspendTestApp/src/**/*.java",
+ "test-apps/DisplayManagerTestApp/src/**/*.java",
],
kotlincflags: [
@@ -90,6 +91,7 @@
"net_flags_lib",
"CtsVirtualDeviceCommonLib",
"com_android_server_accessibility_flags_lib",
+ "locksettings_flags_lib",
],
libs: [
@@ -134,6 +136,7 @@
},
data: [
+ ":DisplayManagerTestApp",
":SimpleServiceTestApp1",
":SimpleServiceTestApp2",
":SimpleServiceTestApp3",
@@ -278,14 +281,22 @@
test_module_config {
name: "FrameworksServicesTests_contentprotection",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.contentprotection"],
}
test_module_config {
name: "FrameworksServicesTests_om",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.om."],
}
@@ -293,7 +304,11 @@
test_module_config {
name: "FrameworksServicesTests_contexthub_presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.location.contexthub."],
// TODO(ron): are these right, does it run anything?
include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -302,7 +317,11 @@
test_module_config {
name: "FrameworksServicesTests_contexthub_postsubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.location.contexthub."],
// TODO(ron): are these right, does it run anything?
include_annotations: ["android.platform.test.annotations.Postsubmit"],
@@ -312,14 +331,22 @@
test_module_config {
name: "FrameworksServicesTests_contentcapture",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.contentcapture"],
}
test_module_config {
name: "FrameworksServicesTests_recoverysystem",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.recoverysystem."],
}
@@ -327,7 +354,11 @@
test_module_config {
name: "FrameworksServicesTests_pm_presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_annotations: ["android.platform.test.annotations.Presubmit"],
include_filters: ["com.android.server.pm."],
}
@@ -335,7 +366,11 @@
test_module_config {
name: "FrameworksServicesTests_pm_postsubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_annotations: ["android.platform.test.annotations.Postsubmit"],
include_filters: ["com.android.server.pm."],
}
@@ -344,21 +379,33 @@
test_module_config {
name: "FrameworksServicesTests_os",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.os."],
}
test_module_config {
name: "FrameworksServicesTests_presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
test_module_config {
name: "FrameworksServicesTests_com_android_server_job_Presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.job"],
exclude_annotations: [
"androidx.test.filters.LargeTest",
@@ -369,49 +416,77 @@
test_module_config {
name: "FrameworksServicesTests_com_android_server_job",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.job"],
}
test_module_config {
name: "FrameworksServicesTests_com_android_server_tare",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.tare"],
}
test_module_config {
name: "FrameworksServicesTests_com_android_server_usage",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.usage"],
}
test_module_config {
name: "FrameworksServicesTests_battery_stats",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.am.BatteryStatsServiceTest"],
}
test_module_config {
name: "FrameworksServicesTests_accessibility",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.accessibility"],
}
test_module_config {
name: "FrameworksServicesTests_binary_transparency",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.BinaryTransparencyServiceTest"],
}
test_module_config {
name: "FrameworksServicesTests_pinner_service",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.PinnerServiceTest"],
exclude_annotations: ["org.junit.Ignore"],
}
@@ -419,7 +494,11 @@
test_module_config {
name: "FrameworksServicesTests_android_server_am_Presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.am."],
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
@@ -427,21 +506,33 @@
test_module_config {
name: "FrameworksServicesTests_android_server_am",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.am."],
}
test_module_config {
name: "FrameworksServicesTests_android_server_appop",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.appop"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_audio",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.audio"],
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
@@ -449,14 +540,22 @@
test_module_config {
name: "FrameworksServicesTests_android_server_compat",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.compat"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_hdmi_Presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.hdmi"],
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
@@ -464,35 +563,55 @@
test_module_config {
name: "FrameworksServicesTests_android_server_hdmi",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.hdmi"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_integrity",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.integrity."],
}
test_module_config {
name: "FrameworksServicesTests_android_server_lights",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.lights"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_locales",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.locales."],
}
test_module_config {
name: "FrameworksServicesTests_android_server_location_contexthub_Presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.location.contexthub."],
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
@@ -500,21 +619,33 @@
test_module_config {
name: "FrameworksServicesTests_android_server_locksettings",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.locksettings."],
}
test_module_config {
name: "FrameworksServicesTests_android_server_logcat",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.logcat"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_net_Presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.net."],
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
@@ -522,28 +653,44 @@
test_module_config {
name: "FrameworksServicesTests_android_server_om",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.om."],
}
test_module_config {
name: "FrameworksServicesTests_android_server_pdb",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.pdb.PersistentDataBlockServiceTest"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_pm_dex",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.pm.dex"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_policy_Presubmit",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.policy."],
include_annotations: ["android.platform.test.annotations.Presubmit"],
}
@@ -551,49 +698,77 @@
test_module_config {
name: "FrameworksServicesTests_android_server_policy",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.policy."],
}
test_module_config {
name: "FrameworksServicesTests_android_server_power",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.power"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_power_hint",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.power.hint"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_powerstats",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.powerstats"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_rollback",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.rollback"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_uri",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.uri."],
}
test_module_config {
name: "FrameworksServicesTests_com_android_server_location_contexthub",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.location.contexthub."],
include_annotations: ["android.platform.test.annotations.Postsubmit"],
}
@@ -601,7 +776,11 @@
test_module_config {
name: "FrameworksServicesTests_android_server_usage",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.usage"],
exclude_filters: ["com.android.server.usage.StorageStatsServiceTest"],
}
@@ -609,14 +788,22 @@
test_module_config {
name: "FrameworksServicesTests_android_server_soundtrigger_middleware",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.soundtrigger_middleware"],
}
test_module_config {
name: "FrameworksServicesTests_android_server_input",
base: "FrameworksServicesTests",
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+
include_filters: ["com.android.server.input"],
}
@@ -792,3 +979,23 @@
],
include_filters: ["com.android.server.input"],
}
+
+test_module_config {
+ name: "FrameworksServicesTests_people_data",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.people.data"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_Presubmit",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index b56af87..5298251 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -35,6 +35,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
+ <option name="test-file-name" value="DisplayManagerTestApp.apk" />
<option name="test-file-name" value="FrameworksServicesTests.apk" />
<option name="test-file-name" value="SuspendTestApp.apk" />
<option name="test-file-name" value="SimpleServiceTestApp1.apk" />
diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java
index bc3a5ca..2ff0c62 100644
--- a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java
@@ -86,7 +86,8 @@
int attributionChainId = AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
- uidState, accessTime, duration, attributionFlags, attributionChainId);
+ uidState, accessTime, duration, attributionFlags, attributionChainId,
+ DiscreteRegistry.ACCESS_TYPE_FINISH_OP);
// Verify in-memory object is correct
fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
@@ -117,7 +118,8 @@
int attributionChainId = 10;
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
- uidState, accessTime, duration, attributionFlags, attributionChainId);
+ uidState, accessTime, duration, attributionFlags, attributionChainId,
+ DiscreteRegistry.ACCESS_TYPE_START_OP);
fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
duration, uidState, opFlags, attributionFlags, attributionChainId);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 2ba3969..87c9db2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -92,6 +92,7 @@
MockLockSettingsContext mContext;
LockSettingsStorageTestable mStorage;
+ LockSettingsStrongAuth mStrongAuth;
Resources mResources;
FakeGateKeeperService mGateKeeperService;
@@ -135,6 +136,7 @@
mFingerprintManager = mock(FingerprintManager.class);
mFaceManager = mock(FaceManager.class);
mPackageManager = mock(PackageManager.class);
+ mStrongAuth = mock(LockSettingsStrongAuth.class);
LocalServices.removeServiceForTest(LockSettingsInternal.class);
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -162,7 +164,7 @@
mInjector =
new LockSettingsServiceTestable.MockInjector(
mContext,
- mStorage,
+ mStorage, mStrongAuth,
mActivityManager,
setUpStorageManagerMock(),
mSpManager,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 93fc071a..abd39b0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -50,6 +50,7 @@
public static class MockInjector extends LockSettingsService.Injector {
private LockSettingsStorage mLockSettingsStorage;
+ private final LockSettingsStrongAuth mStrongAuth;
private IActivityManager mActivityManager;
private IStorageManager mStorageManager;
private SyntheticPasswordManager mSpManager;
@@ -62,12 +63,14 @@
public boolean mIsMainUserPermanentAdmin = false;
public MockInjector(Context context, LockSettingsStorage storage,
+ LockSettingsStrongAuth strongAuth,
IActivityManager activityManager, IStorageManager storageManager,
SyntheticPasswordManager spManager, FakeGsiService gsiService,
RecoverableKeyStoreManager recoverableKeyStoreManager,
UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
super(context);
mLockSettingsStorage = storage;
+ mStrongAuth = strongAuth;
mActivityManager = activityManager;
mStorageManager = storageManager;
mSpManager = spManager;
@@ -89,7 +92,7 @@
@Override
public LockSettingsStrongAuth getStrongAuth() {
- return mock(LockSettingsStrongAuth.class);
+ return mStrongAuth;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 601a016..2868e55 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -17,6 +17,7 @@
package com.android.server.locksettings;
import static android.Manifest.permission.CONFIGURE_FACTORY_RESET_PROTECTION;
+import static android.security.Flags.FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL;
import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -46,6 +47,10 @@
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.gatekeeper.GateKeeperResponse;
import android.text.TextUtils;
@@ -71,6 +76,8 @@
@RunWith(AndroidJUnit4.class)
public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Before
public void setUp() {
@@ -258,6 +265,34 @@
}
@Test
+ @RequiresFlagsEnabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+ public void setLockCredential_forPrimaryUser_clearsStrongAuthWhenFlagIsOn()
+ throws Exception {
+ setCredential(PRIMARY_USER_ID, newPassword("password"));
+
+ verify(mStrongAuth).reportUnlock(PRIMARY_USER_ID);
+ }
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+ public void setLockCredential_forPrimaryUser_leavesStrongAuthWhenFlagIsOff()
+ throws Exception {
+ setCredential(PRIMARY_USER_ID, newPassword("password"));
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
+ @Test
+ public void setLockCredential_forPrimaryUserWithCredential_leavesStrongAuth() throws Exception {
+ setCredential(PRIMARY_USER_ID, newPassword("password"));
+ reset(mStrongAuth);
+
+ setCredential(PRIMARY_USER_ID, newPassword("password2"), newPassword("password"));
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
+ @Test
public void testSetLockCredential_forProfileWithSeparateChallenge_sendsCredentials()
throws Exception {
setCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
@@ -278,6 +313,28 @@
}
@Test
+ @RequiresFlagsEnabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+ public void setLockCredential_profileWithNewSeparateChallenge_clearsStrongAuthWhenFlagIsOn()
+ throws Exception {
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
+
+ setCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
+
+ verify(mStrongAuth).reportUnlock(MANAGED_PROFILE_USER_ID);
+ }
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+ public void setLockCredential_profileWithNewSeparateChallenge_leavesStrongAuthWhenFlagIsOff()
+ throws Exception {
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
+
+ setCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
+ @Test
public void testSetLockCredential_forProfileWithUnifiedChallenge_doesNotSendRandomCredential()
throws Exception {
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
@@ -305,6 +362,67 @@
MANAGED_PROFILE_USER_ID);
}
+
+ @Test
+ public void setLockCredential_primaryWithUnifiedProfileAndCredential_leavesStrongAuthForBoth()
+ throws Exception {
+ final LockscreenCredential oldCredential = newPassword("oldPassword");
+ final LockscreenCredential newCredential = newPassword("newPassword");
+ setCredential(PRIMARY_USER_ID, oldCredential);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ reset(mStrongAuth);
+
+ setCredential(PRIMARY_USER_ID, newCredential, oldCredential);
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+ public void setLockCredential_primaryWithUnifiedProfile_clearsStrongAuthForBothWhenFlagIsOn()
+ throws Exception {
+ final LockscreenCredential credential = newPassword("oldPassword");
+ setCredential(PRIMARY_USER_ID, credential);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ clearCredential(PRIMARY_USER_ID, credential);
+ reset(mStrongAuth);
+
+ setCredential(PRIMARY_USER_ID, credential);
+
+ verify(mStrongAuth).reportUnlock(PRIMARY_USER_ID);
+ verify(mStrongAuth).reportUnlock(MANAGED_PROFILE_USER_ID);
+ }
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+ public void setLockCredential_primaryWithUnifiedProfile_leavesStrongAuthForBothWhenFlagIsOff()
+ throws Exception {
+ final LockscreenCredential credential = newPassword("oldPassword");
+ setCredential(PRIMARY_USER_ID, credential);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ clearCredential(PRIMARY_USER_ID, credential);
+ reset(mStrongAuth);
+
+ setCredential(PRIMARY_USER_ID, credential);
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
+
+ @Test
+ public void setLockCredential_primaryWithUnifiedProfileWithCredential_leavesStrongAuthForBoth()
+ throws Exception {
+ final LockscreenCredential oldCredential = newPassword("oldPassword");
+ final LockscreenCredential newCredential = newPassword("newPassword");
+ setCredential(PRIMARY_USER_ID, oldCredential);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ reset(mStrongAuth);
+
+ setCredential(PRIMARY_USER_ID, newCredential, oldCredential);
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
@Test
public void
testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
@@ -343,6 +461,18 @@
}
@Test
+ public void clearLockCredential_primaryWithUnifiedProfile_leavesStrongAuthForBoth()
+ throws Exception {
+ setCredential(PRIMARY_USER_ID, newPassword("password"));
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ reset(mStrongAuth);
+
+ clearCredential(PRIMARY_USER_ID, newPassword("password"));
+
+ verify(mStrongAuth, never()).reportUnlock(anyInt());
+ }
+
+ @Test
public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials()
throws Exception {
final LockscreenCredential parentPassword = newPassword("parentPassword");
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index d6f7e21..d071c15 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -60,6 +60,9 @@
import android.os.ServiceSpecificException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -70,6 +73,7 @@
import com.android.server.pm.UserManagerInternal;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -108,6 +112,9 @@
0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23,
};
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private Context mContext;
private UserManager mUserManager;
private UserManagerInternal mUserManagerInternal;
@@ -145,7 +152,6 @@
private RebootEscrowProviderInterface mRebootEscrowProviderInUse;
private ConnectivityManager.NetworkCallback mNetworkCallback;
private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer;
- private boolean mWaitForInternet;
MockInjector(
Context context,
@@ -159,7 +165,6 @@
super(context, storage, userManagerInternal);
mRebootEscrow = rebootEscrow;
mServerBased = false;
- mWaitForInternet = false;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -185,7 +190,6 @@
super(context, storage, userManagerInternal);
mRebootEscrow = null;
mServerBased = true;
- mWaitForInternet = false;
RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
@Override
@@ -227,15 +231,6 @@
}
@Override
- public boolean waitForInternet() {
- return mWaitForInternet;
- }
-
- public void setWaitForNetwork(boolean waitForNetworkEnabled) {
- mWaitForInternet = waitForNetworkEnabled;
- }
-
- @Override
public boolean isNetworkConnected() {
return false;
}
@@ -934,10 +929,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternet_success()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -987,10 +982,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternetRemoteException_Failure()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1042,10 +1037,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkUnavailable()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1090,9 +1085,9 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkLost() throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1145,10 +1140,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkAvailableWithDelay()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1204,10 +1199,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_timeoutExhausted()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1264,10 +1259,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForNetwork_retryCountExhausted()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1320,10 +1315,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_ServerBasedWaitForInternet_RetrySuccess()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/Android.bp b/services/tests/servicestests/test-apps/DisplayManagerTestApp/Android.bp
new file mode 100644
index 0000000..962ae9b
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2024 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "DisplayManagerTestApp",
+
+ sdk_version: "current",
+
+ srcs: ["**/*.java"],
+
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/DisplayManagerTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..c0d9d6f
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.servicestests.apps.displaymanagertestapp">
+
+ <application android:label="DisplayEventTestApp">
+ <activity android:name=".DisplayEventActivity"
+ android:exported="true" />
+ </application>
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/OWNERS b/services/tests/servicestests/test-apps/DisplayManagerTestApp/OWNERS
new file mode 100644
index 0000000..e9557f8
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 345010
+
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/src/com/android/servicestests/apps/displaymanagertestapp/DisplayEventActivity.java b/services/tests/servicestests/test-apps/DisplayManagerTestApp/src/com/android/servicestests/apps/displaymanagertestapp/DisplayEventActivity.java
new file mode 100644
index 0000000..07754b2
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/src/com/android/servicestests/apps/displaymanagertestapp/DisplayEventActivity.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 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.servicestests.apps.displaymanagertestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A simple activity manipulating displays and listening to corresponding display events
+ */
+public class DisplayEventActivity extends Activity {
+ private static final String TAG = DisplayEventActivity.class.getSimpleName();
+
+ private static final String TEST_DISPLAYS = "DISPLAYS";
+ private static final String TEST_MESSENGER = "MESSENGER";
+
+ private static final int MESSAGE_LAUNCHED = 1;
+ private static final int MESSAGE_CALLBACK = 2;
+
+ private static final int DISPLAY_ADDED = 1;
+ private static final int DISPLAY_CHANGED = 2;
+ private static final int DISPLAY_REMOVED = 3;
+
+ private int mExpectedDisplayCount;
+ private int mSeenDisplayCount;
+ private Messenger mMessenger;
+ private DisplayManager mDisplayManager;
+ private DisplayManager.DisplayListener mDisplayListener;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+ mExpectedDisplayCount = 0;
+ mSeenDisplayCount = intent.getIntExtra(TEST_DISPLAYS, 0);
+ mMessenger = intent.getParcelableExtra(TEST_MESSENGER, Messenger.class);
+ mDisplayManager = getApplicationContext().getSystemService(DisplayManager.class);
+ mDisplayListener = new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ callback(displayId, DISPLAY_ADDED);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ callback(displayId, DISPLAY_REMOVED);
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ callback(displayId, DISPLAY_CHANGED);
+ }
+ };
+ Handler handler = new Handler(Looper.getMainLooper());
+ mDisplayManager.registerDisplayListener(mDisplayListener, handler);
+ launched();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ }
+
+ private void launched() {
+ try {
+ Message msg = Message.obtain();
+ msg.what = MESSAGE_LAUNCHED;
+ msg.arg1 = Process.myPid();
+ msg.arg2 = Process.myUid();
+ Log.d(TAG, "Launched " + mSeenDisplayCount);
+ mMessenger.send(msg);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ private void callback(int displayId, int event) {
+ try {
+ Message msg = Message.obtain();
+ msg.what = MESSAGE_CALLBACK;
+ msg.arg1 = displayId;
+ msg.arg2 = event;
+ Log.d(TAG, "Msg " + msg.arg1 + " " + msg.arg2);
+ mMessenger.send(msg);
+ if (event == DISPLAY_REMOVED) {
+ mExpectedDisplayCount++;
+ if (mExpectedDisplayCount >= mSeenDisplayCount) {
+ finish();
+ }
+ }
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 850d2f7..a63a38d 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -92,3 +92,13 @@
// Required for TestParameterInjector
javacflags: ["-parameters"],
}
+
+test_module_config {
+ name: "FrameworksUiServicesTests_notification",
+ base: "FrameworksUiServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ exclude_annotations: ["androidx.test.filters.LargeTest"],
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 196bc47..96ddf80 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -99,6 +99,7 @@
import static android.service.notification.Condition.SOURCE_CONTEXT;
import static android.service.notification.Condition.SOURCE_USER_ACTION;
import static android.service.notification.Condition.STATE_TRUE;
+import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -4412,7 +4413,7 @@
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
- eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true);
+ eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true);
reset(mListeners);
mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
@@ -4421,6 +4422,24 @@
}
@Test
+ @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testAppsCannotDeleteBundleChannel() throws Exception {
+ when(mCompanionMgr.getAssociations(mPkg, mUserId))
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
+ eq(NEWS_ID), anyBoolean()))
+ .thenReturn(mTestNotificationChannel);
+ when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
+ eq(NEWS_ID), anyInt(), anyBoolean())).thenReturn(true);
+ reset(mListeners);
+ mBinderService.deleteNotificationChannel(mPkg, NEWS_ID);
+ verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
+ eq(Process.myUserHandle()), any(),
+ eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
+ }
+
+ @Test
public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
when(mCompanionMgr.getAssociations(mPkg, mUserId))
.thenReturn(singletonList(mock(AssociationInfo.class)));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 559c324..1905ae4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -6222,6 +6222,47 @@
.isEqualTo(IMPORTANCE_LOW);
}
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testNotificationBundles_appsCannotUpdate() {
+ // do something that triggers settings creation for an app
+ mHelper.setShowBadge(PKG_O, UID_O, true);
+
+ NotificationChannel fromApp =
+ new NotificationChannel(NEWS_ID, "The best channel", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, fromApp, true, false, UID_O, false);
+
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, NEWS_ID, false).getImportance())
+ .isEqualTo(IMPORTANCE_LOW);
+ }
+
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testNotificationBundles_osCanAllowToBypassDnd() {
+ // do something that triggers settings creation for an app
+ mHelper.setShowBadge(PKG_O, UID_O, true);
+
+ NotificationChannel fromApp =
+ new NotificationChannel(NEWS_ID, "The best channel", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, fromApp, true, false, UID_O, false);
+ }
+
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testUnDeleteBundleChannelsOnLoadIfNotUserChange() throws Exception {
+ mHelper.setShowBadge(PKG_P, UID_P, true);
+ // the public create/update methods should prevent this, so take advantage of the fact that
+ // the object is in the same process
+ mHelper.getNotificationChannel(PKG_P, UID_P, SOCIAL_MEDIA_ID, true).setDeleted(true);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
+ UserHandle.USER_ALL, SOCIAL_MEDIA_ID);
+
+ loadStreamXml(baos, false, UserHandle.USER_ALL);
+
+ assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, SOCIAL_MEDIA_ID, true).
+ isDeleted()).isFalse();
+ }
@Test
public void testRestoredWithoutUid_threadSafety() throws Exception {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index f8ff1f4..efcf027 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -756,7 +756,7 @@
assertEquals("a", fromXml.getPkg());
fromXml.condition = new Condition(Uri.EMPTY, "", Condition.STATE_TRUE);
- assertTrue(fromXml.isAutomaticActive());
+ assertTrue(fromXml.isActive());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index baa633f..39a9d30 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -5788,7 +5788,7 @@
// ... but it is NOT active
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
- assertThat(storedRule.isAutomaticActive()).isFalse();
+ assertThat(storedRule.isActive()).isFalse();
assertThat(storedRule.isTrueOrUnknown()).isFalse();
assertThat(storedRule.condition).isNull();
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
@@ -5841,7 +5841,7 @@
// ... but it is NEITHER active NOR snoozed.
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
- assertThat(storedRule.isAutomaticActive()).isFalse();
+ assertThat(storedRule.isActive()).isFalse();
assertThat(storedRule.isTrueOrUnknown()).isFalse();
assertThat(storedRule.condition).isNull();
assertThat(storedRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
@@ -6619,7 +6619,7 @@
new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
assertThat(zenRule.condition).isNull();
@@ -6627,14 +6627,14 @@
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isNull();
// Bonus check: app has resumed control over the rule and can now turn it on.
mZenModeHelper.setAutomaticZenRuleState(ruleId, autoOn, ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOn);
}
@@ -6655,7 +6655,7 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId, autoOn, ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOn);
@@ -6663,7 +6663,7 @@
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
assertThat(zenRule.condition).isEqualTo(autoOn);
@@ -6671,14 +6671,14 @@
new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOn);
// Bonus check: app has resumed control over the rule and can now turn it off.
mZenModeHelper.setAutomaticZenRuleState(ruleId, autoOff, ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOff);
}
@@ -6696,7 +6696,7 @@
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
ZenRule zenRuleOn = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRuleOn.isAutomaticActive()).isTrue();
+ assertThat(zenRuleOn.isActive()).isTrue();
assertThat(zenRuleOn.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRuleOn.condition).isNotNull();
@@ -6704,7 +6704,7 @@
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
ZenRule zenRuleOff = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRuleOff.isAutomaticActive()).isFalse();
+ assertThat(zenRuleOff.isActive()).isFalse();
assertThat(zenRuleOff.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
assertThat(zenRuleOff.condition).isNotNull();
}
@@ -6723,27 +6723,27 @@
new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off", STATE_FALSE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off", STATE_FALSE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
}
@Test
@@ -6760,35 +6760,35 @@
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off", STATE_FALSE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6805,14 +6805,14 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-on-from-sysui", STATE_TRUE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
// ... and they can turn it off manually from inside the app.
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-off-from-app", STATE_FALSE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isFalse();
+ assertThat(getZenRule(ruleId).isActive()).isFalse();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6829,21 +6829,21 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on-from-app", STATE_TRUE,
SOURCE_SCHEDULE), ORIGIN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
// User manually turns off rule from SysUI / Settings...
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-off-from-sysui", STATE_FALSE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isFalse();
+ assertThat(getZenRule(ruleId).isActive()).isFalse();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
// ... and they can turn it on manually from inside the app.
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-on-from-app", STATE_TRUE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6861,14 +6861,14 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-on-from-app", STATE_TRUE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
// ... so the app can turn it off when its schedule is over.
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off-from-app", STATE_FALSE,
SOURCE_SCHEDULE), ORIGIN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isFalse();
+ assertThat(getZenRule(ruleId).isActive()).isFalse();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index c706d52..c176658 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -932,7 +932,6 @@
WindowProcessController wpc = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
- mAtm.mInternal.onProcessAdded(wpc);
ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal
.getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
@@ -987,7 +986,6 @@
WindowProcessController wpc = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
- mAtm.mInternal.onProcessAdded(wpc);
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME,
@@ -1018,7 +1016,6 @@
WindowProcessController wpc = createWindowProcessController(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
- mAtm.mInternal.onProcessAdded(wpc);
ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME,
@@ -1048,6 +1045,7 @@
WindowProcessController wpc = new WindowProcessController(
mAtm, info, packageName, 0, userId, null, mMockListener);
mAtm.mInternal.preBindApplication(wpc, info);
+ mAtm.mInternal.onProcessAdded(wpc);
wpc.setThread(mock(IApplicationThread.class));
return wpc;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index 5a3ae76..a48813d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -16,11 +16,17 @@
package com.android.server.wm;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -33,10 +39,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -55,6 +61,8 @@
import android.hardware.camera2.CameraManager;
import android.os.Handler;
import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.Surface;
import androidx.test.filters.SmallTest;
@@ -134,6 +142,7 @@
new CameraCompatFreeformPolicy(mDisplayContent, cameraStateMonitor,
mActivityRefresher);
+ setDisplayRotation(Surface.ROTATION_90);
mCameraCompatFreeformPolicy.start();
cameraStateMonitor.startListeningToCameraState();
}
@@ -162,17 +171,49 @@
}
@Test
- public void testCameraConnected_activatesCameraCompatMode() throws Exception {
+ public void testCameraConnected_deviceInPortrait_portraitCameraCompatMode() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ setDisplayRotation(Surface.ROTATION_0);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
- assertInCameraCompatMode();
+ assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT);
+ assertActivityRefreshRequested(/* refreshRequested */ false);
+ }
+
+ @Test
+ public void testCameraConnected_deviceInLandscape_portraitCameraCompatMode() throws Exception {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ setDisplayRotation(Surface.ROTATION_270);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
+ assertActivityRefreshRequested(/* refreshRequested */ false);
+ }
+
+ @Test
+ public void testCameraConnected_deviceInPortrait_landscapeCameraCompatMode() throws Exception {
+ configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
+ setDisplayRotation(Surface.ROTATION_0);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT);
+ assertActivityRefreshRequested(/* refreshRequested */ false);
+ }
+
+ @Test
+ public void testCameraConnected_deviceInLandscape_landscapeCameraCompatMode() throws Exception {
+ configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
+ setDisplayRotation(Surface.ROTATION_270);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE);
assertActivityRefreshRequested(/* refreshRequested */ false);
}
@Test
public void testCameraReconnected_cameraCompatModeAndRefresh() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ setDisplayRotation(Surface.ROTATION_270);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity);
@@ -180,7 +221,7 @@
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity);
- assertInCameraCompatMode();
+ assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
assertActivityRefreshRequested(/* refreshRequested */ true);
}
@@ -285,16 +326,14 @@
doReturn(true).when(mActivity).inFreeformWindowingMode();
}
- private void assertInCameraCompatMode() {
- assertNotEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
- mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ private void assertInCameraCompatMode(@CameraCompatTaskInfo.FreeformCameraCompatMode int mode) {
+ assertEquals(mode, mActivity.mAppCompatController.getAppCompatCameraOverrides()
.getFreeformCameraCompatMode());
}
private void assertNotInCameraCompatMode() {
- assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
- mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .getFreeformCameraCompatMode());
+ assertEquals(CAMERA_COMPAT_FREEFORM_NONE, mActivity.mAppCompatController
+ .getAppCompatCameraOverrides().getFreeformCameraCompatMode());
}
private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
@@ -328,4 +367,19 @@
configuration.windowConfiguration.setAppBounds(bounds);
return configuration;
}
+
+ private void setDisplayRotation(@Surface.Rotation int displayRotation) {
+ doAnswer(invocation -> {
+ DisplayInfo displayInfo = new DisplayInfo();
+ mDisplayContent.getDisplay().getDisplayInfo(displayInfo);
+ displayInfo.rotation = displayRotation;
+ // Set height so that the natural orientation (rotation is 0) is portrait. This is the
+ // case for most standard phones and tablets.
+ // TODO(b/365725400): handle landscape natural orientation.
+ displayInfo.logicalHeight = displayRotation % 180 == 0 ? 800 : 600;
+ displayInfo.logicalWidth = displayRotation % 180 == 0 ? 600 : 800;
+ return displayInfo;
+ }).when(mDisplayContent.mWmService.mDisplayManagerInternal)
+ .getDisplayInfo(anyInt());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 2f2b473..b7aa730 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -45,6 +45,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+import com.android.server.wm.TestDisplayWindowSettingsProvider.TestStorage;
import org.junit.After;
import org.junit.Before;
@@ -516,81 +517,4 @@
}
return fullyDeleted;
}
-
- /** In-memory storage implementation. */
- public class TestStorage implements DisplayWindowSettingsProvider.WritableSettingsStorage {
- private InputStream mReadStream;
- private ByteArrayOutputStream mWriteStream;
-
- private boolean mWasSuccessful;
-
- /**
- * Returns input stream for reading. By default tries forward the output stream if previous
- * write was successful.
- * @see #closeRead()
- */
- @Override
- public InputStream openRead() throws FileNotFoundException {
- if (mReadStream == null && mWasSuccessful) {
- mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
- }
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.mark(Integer.MAX_VALUE);
- }
- return mReadStream;
- }
-
- /** Must be called after each {@link #openRead} to reset the position in the stream. */
- void closeRead() throws IOException {
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.reset();
- }
- mReadStream = null;
- }
-
- /**
- * Creates new or resets existing output stream for write. Automatically closes previous
- * read stream, since following reads should happen based on this new write.
- */
- @Override
- public OutputStream startWrite() throws IOException {
- if (mWriteStream == null) {
- mWriteStream = new ByteArrayOutputStream();
- } else {
- mWriteStream.reset();
- }
- if (mReadStream != null) {
- closeRead();
- }
- return mWriteStream;
- }
-
- @Override
- public void finishWrite(OutputStream os, boolean success) {
- mWasSuccessful = success;
- try {
- os.close();
- } catch (IOException e) {
- // This method can't throw IOException since the super implementation doesn't, so
- // we just wrap it in a RuntimeException so we end up crashing the test all the
- // same.
- throw new RuntimeException(e);
- }
- }
-
- /** Overrides the read stream of the injector. By default it uses current write stream. */
- private void setReadStream(InputStream is) {
- mReadStream = is;
- }
-
- private boolean wasWriteSuccessful() {
- return mWasSuccessful;
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 71cfbfd..08622e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -133,6 +133,7 @@
private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners =
new ArrayList<>();
+ private AppCompatConfiguration mAppCompat;
private Description mDescription;
private Context mContext;
private StaticMockitoSession mMockitoSession;
@@ -379,6 +380,11 @@
mock(ActivityManagerService.class, withSettings().stubOnly());
mAtmService = new TestActivityTaskManagerService(mContext, amService);
LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
+
+ // AppCompatConfiguration
+ mAppCompat = new AppCompatConfiguration(
+ ActivityThread.currentActivityThread().getSystemUiContext());
+
// Create a fake WindowProcessController for the system process.
final WindowProcessController wpc =
addProcess("android", "system", 1485 /* pid */, 1000 /* uid */);
@@ -394,7 +400,7 @@
mWmService = WindowManagerService.main(
mContext, mImService, false, wmPolicy, mAtmService,
testDisplayWindowSettingsProvider, StubTransaction::new,
- MockSurfaceControlBuilder::new);
+ MockSurfaceControlBuilder::new, mAppCompat);
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 45082d2..7ff2e50 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -71,7 +73,6 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.CameraCompatTaskInfo;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -2025,10 +2026,10 @@
public void getTaskInfoPropagatesCameraCompatMode() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = task.getTopMostActivity();
- activity.mAppCompatController.getAppCompatCameraOverrides()
- .setFreeformCameraCompatMode(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT);
+ activity.mAppCompatController.getAppCompatCameraOverrides().setFreeformCameraCompatMode(
+ CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
- assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT,
+ assertEquals(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE,
task.getTaskInfo().appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
index e11df98..877f65c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
@@ -22,6 +22,16 @@
import java.util.HashMap;
import java.util.Map;
+import com.android.server.wm.DisplayWindowSettingsProvider.WritableSettingsStorage;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
/**
* In-memory DisplayWindowSettingsProvider used in tests. Ensures no settings are read from or
* written to device-specific display settings files.
@@ -30,6 +40,10 @@
private final Map<String, SettingsEntry> mOverrideSettingsMap = new HashMap<>();
+ public TestDisplayWindowSettingsProvider() {
+ super(new TestStorage(), new TestStorage());
+ }
+
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
@@ -76,4 +90,81 @@
private static String getIdentifier(DisplayInfo displayInfo) {
return displayInfo.uniqueId;
}
+
+ /** In-memory storage implementation. */
+ public static class TestStorage implements WritableSettingsStorage {
+ private InputStream mReadStream;
+ private ByteArrayOutputStream mWriteStream;
+
+ private boolean mWasSuccessful;
+
+ /**
+ * Returns input stream for reading. By default tries forward the output stream if previous
+ * write was successful.
+ * @see #closeRead()
+ */
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ if (mReadStream == null && mWasSuccessful) {
+ mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+ }
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.mark(Integer.MAX_VALUE);
+ }
+ return mReadStream;
+ }
+
+ /** Must be called after each {@link #openRead} to reset the position in the stream. */
+ public void closeRead() throws IOException {
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.reset();
+ }
+ mReadStream = null;
+ }
+
+ /**
+ * Creates new or resets existing output stream for write. Automatically closes previous
+ * read stream, since following reads should happen based on this new write.
+ */
+ @Override
+ public OutputStream startWrite() throws IOException {
+ if (mWriteStream == null) {
+ mWriteStream = new ByteArrayOutputStream();
+ } else {
+ mWriteStream.reset();
+ }
+ if (mReadStream != null) {
+ closeRead();
+ }
+ return mWriteStream;
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ mWasSuccessful = success;
+ try {
+ os.close();
+ } catch (IOException e) {
+ // This method can't throw IOException since the super implementation doesn't, so
+ // we just wrap it in a RuntimeException so we end up crashing the test all the
+ // same.
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Overrides the read stream of the injector. By default it uses current write stream. */
+ public void setReadStream(InputStream is) {
+ mReadStream = is;
+ }
+
+ public boolean wasWriteSuccessful() {
+ return mWasSuccessful;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5a54af1..2d5e5da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -80,6 +80,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
@@ -88,9 +89,12 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.IBinder;
import android.os.InputConfig;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.ArraySet;
@@ -116,6 +120,7 @@
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.wm.SensitiveContentPackages.PackageInfo;
+import com.android.window.flags.Flags;
import org.junit.After;
import org.junit.Test;
@@ -965,6 +970,88 @@
assertTrue(testFlag(handle.inputConfig, InputConfig.NO_INPUT_CHANNEL));
}
+ @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesLetterboxBoundsIfTransformedBoundsAndLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
+ final Rect transformedBounds = new Rect(0, 0, 300, 500);
+ doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
+ // touchable region should match letterboxInnerBounds always.
+ assertEquals(letterboxInnerBounds, outRegion.getBounds());
+ }
+
+ @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesLetterboxBoundsIfNullTransformedBoundsAndLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Fragment bounds used for size of touchable region if letterbox inner bounds are empty
+ // and Transform bounds are null.
+ doReturn(null).when(win.mToken).getFixedRotationTransformDisplayBounds();
+ final Rect fragmentBounds = new Rect(0, 0, 300, 500);
+ final TaskFragment taskFragment = win.mActivityRecord.getTaskFragment();
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(fragmentBounds);
+ return null;
+ }).when(taskFragment).getDimBounds(any());
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
+ // touchable region should match letterboxInnerBounds always.
+ assertEquals(letterboxInnerBounds, outRegion.getBounds());
+ }
+
+ @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesTransformedBoundsIfLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
+ final Rect transformedBounds = new Rect(0, 0, 300, 500);
+ doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is enabled and transformedBounds are non-null,
+ // touchable region should match transformedBounds.
+ assertEquals(transformedBounds, outRegion.getBounds());
+ }
+
@Test
public void testHasActiveVisibleWindow() {
final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
index c45b99d..4104999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -28,6 +28,7 @@
import static java.io.File.createTempFile;
import static java.nio.file.Files.createTempDirectory;
+import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.Presubmit;
import android.tools.ScenarioBuilder;
import android.tools.traces.io.ResultWriter;
@@ -35,107 +36,187 @@
import android.view.Choreographer;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.After;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
+import perfetto.protos.PerfettoConfig.TracingServiceState;
import perfetto.protos.PerfettoConfig.WindowManagerConfig.LogFrequency;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Optional;
+
/**
* Test class for {@link WindowTracingPerfetto}.
*/
@SmallTest
@Presubmit
public class WindowTracingPerfettoTest {
- private WindowManagerService mWmMock;
- private Choreographer mChoreographer;
- private WindowTracing mWindowTracing;
+ private static final String TEST_DATA_SOURCE_NAME = "android.windowmanager.test";
+
+ private static WindowManagerService sWmMock;
+ private static Choreographer sChoreographer;
+ private static WindowTracing sWindowTracing;
+
private PerfettoTraceMonitor mTraceMonitor;
- private ResultWriter mWriter;
+
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
+ sWmMock = Mockito.mock(WindowManagerService.class);
+ Mockito.doNothing().when(sWmMock).dumpDebugLocked(Mockito.any(), Mockito.anyInt());
+ sChoreographer = Mockito.mock(Choreographer.class);
+ sWindowTracing = new WindowTracingPerfetto(sWmMock, sChoreographer,
+ new WindowManagerGlobalLock(), TEST_DATA_SOURCE_NAME);
+ waitDataSourceIsAvailable();
+ }
@Before
- public void setUp() throws Exception {
- mWmMock = Mockito.mock(WindowManagerService.class);
- Mockito.doNothing().when(mWmMock).dumpDebugLocked(Mockito.any(), Mockito.anyInt());
-
- mChoreographer = Mockito.mock(Choreographer.class);
-
- mWindowTracing = new WindowTracingPerfetto(mWmMock, mChoreographer,
- new WindowManagerGlobalLock());
-
- mWriter = new ResultWriter()
- .forScenario(new ScenarioBuilder()
- .forClass(createTempFile("temp", "").getName()).build())
- .withOutputDir(createTempDirectory("temp").toFile())
- .setRunComplete();
+ public void setUp() throws IOException {
+ Mockito.clearInvocations(sWmMock);
}
@After
- public void tearDown() throws Exception {
+ public void tearDown() throws IOException {
stopTracing();
}
@Test
public void isEnabled_returnsFalseByDefault() {
- assertFalse(mWindowTracing.isEnabled());
+ assertFalse(sWindowTracing.isEnabled());
}
@Test
- public void isEnabled_returnsTrueAfterStartThenFalseAfterStop() {
+ public void isEnabled_returnsTrueAfterStartThenFalseAfterStop() throws IOException {
startTracing(false);
- assertTrue(mWindowTracing.isEnabled());
+ assertTrue(sWindowTracing.isEnabled());
stopTracing();
- assertFalse(mWindowTracing.isEnabled());
+ assertFalse(sWindowTracing.isEnabled());
}
@Test
public void trace_ignoresLogStateCalls_ifTracingIsDisabled() {
- mWindowTracing.logState("where");
- verifyZeroInteractions(mWmMock);
+ sWindowTracing.logState("where");
+ verifyZeroInteractions(sWmMock);
}
@Test
- public void trace_writesInitialStateSnapshot_whenTracingStarts() throws Exception {
+ public void trace_writesInitialStateSnapshot_whenTracingStarts() {
startTracing(false);
- verify(mWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
+ verify(sWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
}
@Test
- public void trace_writesStateSnapshot_onLogStateCall() throws Exception {
+ public void trace_writesStateSnapshot_onLogStateCall() {
startTracing(false);
- mWindowTracing.logState("where");
- verify(mWmMock, times(2)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
+ sWindowTracing.logState("where");
+ verify(sWmMock, times(2)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
}
@Test
- public void dump_writesOneSingleStateSnapshot() throws Exception {
+ public void dump_writesOneSingleStateSnapshot() {
startTracing(true);
- mWindowTracing.logState("where");
- verify(mWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
+ sWindowTracing.logState("where");
+ verify(sWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
}
private void startTracing(boolean isDump) {
if (isDump) {
mTraceMonitor = PerfettoTraceMonitor
.newBuilder()
- .enableWindowManagerDump()
+ .enableWindowManagerDump(TEST_DATA_SOURCE_NAME)
.build();
} else {
mTraceMonitor = PerfettoTraceMonitor
.newBuilder()
- .enableWindowManagerTrace(LogFrequency.LOG_FREQUENCY_TRANSACTION)
+ .enableWindowManagerTrace(LogFrequency.LOG_FREQUENCY_TRANSACTION,
+ TEST_DATA_SOURCE_NAME)
.build();
}
mTraceMonitor.start();
}
- private void stopTracing() {
+ private void stopTracing() throws IOException {
if (mTraceMonitor == null || !mTraceMonitor.isEnabled()) {
return;
}
- mTraceMonitor.stop(mWriter);
+
+ ResultWriter writer = new ResultWriter()
+ .forScenario(new ScenarioBuilder()
+ .forClass(createTempFile("temp", "").getName()).build())
+ .withOutputDir(createTempDirectory("temp").toFile())
+ .setRunComplete();
+
+ mTraceMonitor.stop(writer);
+ }
+
+ private static void waitDataSourceIsAvailable() {
+ final int timeoutMs = 10000;
+ final int busyWaitIntervalMs = 100;
+
+ int elapsedMs = 0;
+
+ while (!isDataSourceAvailable()) {
+ try {
+ Thread.sleep(busyWaitIntervalMs);
+ elapsedMs += busyWaitIntervalMs;
+ if (elapsedMs >= timeoutMs) {
+ throw new RuntimeException("Data source didn't become available."
+ + " Waited for: " + timeoutMs + " ms");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static boolean isDataSourceAvailable() {
+ byte[] proto = executeShellCommand("perfetto --query-raw");
+
+ try {
+ TracingServiceState state = TracingServiceState.parseFrom(proto);
+
+ Optional<Integer> producerId = Optional.empty();
+
+ for (TracingServiceState.Producer producer : state.getProducersList()) {
+ if (producer.getPid() == android.os.Process.myPid()) {
+ producerId = Optional.of(producer.getId());
+ break;
+ }
+ }
+
+ if (producerId.isEmpty()) {
+ return false;
+ }
+
+ for (TracingServiceState.DataSource ds : state.getDataSourcesList()) {
+ if (ds.getDsDescriptor().getName().equals(TEST_DATA_SOURCE_NAME)
+ && ds.getProducerId() == producerId.get()) {
+ return true;
+ }
+ }
+ } catch (InvalidProtocolBufferException e) {
+ throw new RuntimeException(e);
+ }
+
+ return false;
+ }
+
+ private static byte[] executeShellCommand(String command) {
+ try {
+ ParcelFileDescriptor fd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeShellCommand(command);
+ FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(fd);
+ return is.readAllBytes();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
index 579fda3..a0f01bd 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
@@ -50,4 +50,11 @@
* Satellite location is based on magnetic north direction.
*/
void onSatellitePositionChanged(in PointingInfo pointingInfo);
+
+ /**
+ * Called when framework receives a request to send a datagram.
+ *
+ * @param datagramType The type of the requested datagram.
+ */
+ void onSendDatagramRequested(int datagramType);
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 284e2bd..90dae3b 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -1220,6 +1220,12 @@
() -> callback.onReceiveDatagramStateChanged(
state, receivePendingCount, errorCode)));
}
+
+ @Override
+ public void onSendDatagramRequested(int datagramType) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> callback.onSendDatagramRequested(datagramType)));
+ }
};
sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
telephony.startSatelliteTransmissionUpdates(errorCallback, internalCallback);
diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
index d8bd662..046ae5f 100644
--- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
@@ -75,4 +75,13 @@
void onReceiveDatagramStateChanged(
@SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount,
@SatelliteManager.SatelliteResult int errorCode);
+
+ /**
+ * Called when framework receives a request to send a datagram.
+ *
+ * @param datagramType The type of the requested datagram.
+ *
+ * @hide
+ */
+ default void onSendDatagramRequested(@SatelliteManager.DatagramType int datagramType) {}
}
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index 67825d2..3753b23 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -23,7 +23,6 @@
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.flicker.subject.region.RegionSubject
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
@@ -41,9 +40,8 @@
* Transitions: From A launch a trampoline Activity T, T launches secondary Activity B and finishes
* itself, end up in split A|B.
*
- * To run this test: `atest FlickerTestsOther:OpenTrampolineActivityTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:OpenTrampolineActivityTest`
*/
-@FlakyTest(bugId = 341209752)
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 4a675be..0bcd2f3 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,6 +17,7 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.os.SystemClock
import android.tools.PlatformConsts
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.helpers.FIND_TIMEOUT
@@ -25,6 +26,7 @@
import android.tools.traces.parsers.toFlickerComponent
import android.util.Log
import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
import androidx.test.uiautomator.Until
import androidx.window.extensions.WindowExtensions
import androidx.window.extensions.WindowExtensionsProvider
@@ -83,6 +85,7 @@
* activity and finish itself.
*/
fun launchTrampolineActivity(wmHelper: WindowManagerStateHelper) {
+ scrollToBottom()
val launchButton =
uiDevice.wait(
Until.findObject(By.res(packageName, "launch_trampoline_button")),
@@ -210,6 +213,7 @@
* placeholder secondary activity based on the placeholder rule.
*/
fun launchPlaceholderSplitRTL(wmHelper: WindowManagerStateHelper) {
+ scrollToBottom()
val launchButton =
uiDevice.wait(
Until.findObject(By.res(packageName, "launch_placeholder_split_rtl_button")),
@@ -224,6 +228,21 @@
.waitForAndVerify()
}
+ /**
+ * Scrolls to the bottom of the launch options. This is needed if the launch button is at the
+ * bottom. Otherwise the click may trigger touch on navBar.
+ */
+ private fun scrollToBottom() {
+ val launchOptionsList = uiDevice.wait(
+ Until.findObject(By.res(packageName, "launch_options_list")),
+ FIND_TIMEOUT
+ )
+ requireNotNull(launchOptionsList) { "Unable to find the list of launch options" }
+ launchOptionsList.scrollUntil(Direction.DOWN, Until.scrollFinished(Direction.DOWN))
+ // Wait a bit after scrolling, otherwise the immediate click may not be treated as "click".
+ SystemClock.sleep(1000L)
+ }
+
companion object {
private const val TAG = "ActivityEmbeddingAppHelper"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index 917aec1..939ba81 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -21,8 +21,10 @@
android:background="@android:color/holo_orange_light">
<LinearLayout
+ android:id="@+id/launch_options_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingBottom="48dp"
android:orientation="vertical">
<Button
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
index a05d08c..914adc4 100644
--- a/tests/Input/AndroidManifest.xml
+++ b/tests/Input/AndroidManifest.xml
@@ -32,6 +32,14 @@
android:process=":externalProcess">
</activity>
+ <activity android:name="com.android.test.input.CaptureEventActivity"
+ android:label="Capture events"
+ android:configChanges="touchscreen|uiMode|orientation|screenSize|screenLayout|keyboardHidden|uiMode|navigation|keyboard|density|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize"
+ android:enableOnBackInvokedCallback="false"
+ android:turnScreenOn="true"
+ android:exported="true">
+ </activity>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.input"
diff --git a/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu b/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu
new file mode 100644
index 0000000..1a9112b
--- /dev/null
+++ b/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu
@@ -0,0 +1,150 @@
+# EVEMU 1.2
+# One finger swipe gesture on the Google Pixel Tablet touchscreen
+N: NVTCapacitiveTouchScreen
+I: 001c 0603 7806 0100
+P: 02 00 00 00 00 00 00 00
+B: 00 0b 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 80 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 04 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 02 00 00 00 00 00 00 00 00
+B: 03 00 00 00 00 00 80 f3 46
+B: 04 00 00 00 00 00 00 00 00
+B: 05 00 00 00 00 00 00 00 00
+B: 11 00 00 00 00 00 00 00 00
+B: 12 00 00 00 00 00 00 00 00
+A: 2f 0 9 0 0 0
+A: 30 0 2559 0 0 11
+A: 31 0 1599 0 0 11
+A: 34 -4096 4096 0 0 0
+A: 35 0 1599 0 0 11
+A: 36 0 2559 0 0 11
+A: 37 0 2 0 0 0
+A: 39 0 65535 0 0 0
+A: 3a 0 256 0 0 0
+A: 3e 0 8 0 0 0
+E: 0.000001 0001 014a 0001
+E: 0.000001 0003 0039 0003
+E: 0.000001 0003 0035 0810
+E: 0.000001 0003 0036 1650
+E: 0.000001 0003 0030 0082
+E: 0.000001 0003 0031 0077
+E: 0.000001 0003 003a 0215
+E: 0.000001 0003 0034 3218
+E: 0.000001 0000 0000 0000
+E: 0.008818 0003 0035 0825
+E: 0.008818 0003 0036 1645
+E: 0.008818 0003 0034 3217
+E: 0.008818 0000 0000 0000
+E: 0.016306 0003 0035 0841
+E: 0.016306 0003 0036 1639
+E: 0.016306 0003 0034 3102
+E: 0.016306 0000 0000 0000
+E: 0.025653 0003 0035 0862
+E: 0.025653 0003 0036 1630
+E: 0.025653 0003 0034 3092
+E: 0.025653 0000 0000 0000
+E: 0.032936 0003 0035 0883
+E: 0.032936 0003 0036 1619
+E: 0.032936 0003 0034 3030
+E: 0.032936 0000 0000 0000
+E: 0.042072 0003 0035 0905
+E: 0.042072 0003 0036 1604
+E: 0.042072 0003 0034 2848
+E: 0.042072 0000 0000 0000
+E: 0.049569 0003 0035 0924
+E: 0.049569 0003 0036 1591
+E: 0.049569 0003 0034 2830
+E: 0.049569 0000 0000 0000
+E: 0.058706 0003 0035 0942
+E: 0.058706 0003 0036 1573
+E: 0.058706 0000 0000 0000
+E: 0.066207 0003 0035 0954
+E: 0.066207 0003 0036 1557
+E: 0.066207 0003 0034 2790
+E: 0.066207 0000 0000 0000
+E: 0.075337 0003 0035 0966
+E: 0.075337 0003 0036 1535
+E: 0.075337 0000 0000 0000
+E: 0.082841 0003 0035 0973
+E: 0.082841 0003 0036 1511
+E: 0.082841 0003 0034 2788
+E: 0.082841 0000 0000 0000
+E: 0.091972 0003 0035 0971
+E: 0.091972 0003 0036 1480
+E: 0.091972 0003 0034 2770
+E: 0.091972 0000 0000 0000
+E: 0.099474 0003 0035 0961
+E: 0.099474 0003 0036 1445
+E: 0.099474 0003 0034 2644
+E: 0.099474 0000 0000 0000
+E: 0.108631 0003 0035 0937
+E: 0.108631 0003 0036 1400
+E: 0.108631 0003 0030 0083
+E: 0.108631 0003 0034 2461
+E: 0.108631 0000 0000 0000
+E: 0.116109 0003 0035 0909
+E: 0.116109 0003 0036 1361
+E: 0.116109 0003 0034 2278
+E: 0.116109 0000 0000 0000
+E: 0.125263 0003 0035 0865
+E: 0.125263 0003 0036 1311
+E: 0.125263 0003 0034 2096
+E: 0.125263 0000 0000 0000
+E: 0.132741 0003 0035 0820
+E: 0.132741 0003 0036 1261
+E: 0.132741 0003 0034 2083
+E: 0.132741 0000 0000 0000
+E: 0.141876 0003 0035 0755
+E: 0.141876 0003 0036 1193
+E: 0.141876 0003 003a 0216
+E: 0.141876 0003 0034 2266
+E: 0.141876 0000 0000 0000
+E: 0.149376 0003 0035 0691
+E: 0.149376 0003 0036 1124
+E: 0.149376 0003 0034 2448
+E: 0.149376 0000 0000 0000
+E: 0.158510 0003 0035 0609
+E: 0.158510 0003 0036 1033
+E: 0.158510 0003 0034 2631
+E: 0.158510 0000 0000 0000
+E: 0.166011 0003 0035 0543
+E: 0.166011 0003 0036 0957
+E: 0.166011 0003 0034 2813
+E: 0.166011 0000 0000 0000
+E: 0.175182 0003 0035 0471
+E: 0.175182 0003 0036 0864
+E: 0.175182 0003 0031 0076
+E: 0.175182 0003 0034 2996
+E: 0.175182 0000 0000 0000
+E: 0.182683 0003 0035 0417
+E: 0.182683 0003 0036 0792
+E: 0.182683 0003 003a 0214
+E: 0.182683 0003 0034 3178
+E: 0.182683 0000 0000 0000
+E: 0.191777 0003 0035 0361
+E: 0.191777 0003 0036 0719
+E: 0.191777 0003 0031 0075
+E: 0.191777 0003 003a 0213
+E: 0.191777 0003 0034 2996
+E: 0.191777 0000 0000 0000
+E: 0.199431 0003 0035 0271
+E: 0.199431 0003 0036 0603
+E: 0.199431 0003 0030 0060
+E: 0.199431 0003 0031 0029
+E: 0.199431 0003 003a 0060
+E: 0.199431 0003 0034 2813
+E: 0.199431 0000 0000 0000
+E: 0.207943 0003 003a 0000
+E: 0.207943 0003 0039 -001
+E: 0.207943 0001 014a 0000
+E: 0.207943 0000 0000 0000
diff --git a/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json b/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json
new file mode 100644
index 0000000..df4f9fb
--- /dev/null
+++ b/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json
@@ -0,0 +1,34 @@
+[
+ {
+ "name": "One finger swipe",
+ "source": "TOUCHSCREEN",
+ "events": [
+ {"action":"DOWN","axes":{"AXIS_X":810,"AXIS_Y":1650,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.234087586402893},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":825,"AXIS_Y":1645,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.2337040901184082},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":841,"AXIS_Y":1639,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1896021366119385},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":862,"AXIS_Y":1630,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1857671737670898},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":883,"AXIS_Y":1619,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1619905233383179},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":905,"AXIS_Y":1604,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0921943187713623},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":924,"AXIS_Y":1591,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0852913856506348},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":942,"AXIS_Y":1573,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0852913856506348},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":954,"AXIS_Y":1557,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0699516534805298},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":966,"AXIS_Y":1535,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0699516534805298},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":973,"AXIS_Y":1511,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.06918466091156},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":971,"AXIS_Y":1480,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0622817277908325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":961,"AXIS_Y":1445,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0139613151550293},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":937,"AXIS_Y":1400,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.9437817335128784},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":909,"AXIS_Y":1361,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.8736020922660828},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":865,"AXIS_Y":1311,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.803805947303772},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":820,"AXIS_Y":1261,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.7988204956054688},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":755,"AXIS_Y":1193,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.8690001368522644},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":691,"AXIS_Y":1124,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.9387962818145752},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":609,"AXIS_Y":1033,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.008975863456726},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":543,"AXIS_Y":957,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":471,"AXIS_Y":864,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":76,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":76,"AXIS_ORIENTATION":1.1489516496658325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":417,"AXIS_Y":792,"AXIS_PRESSURE":0.8359375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":76,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":76,"AXIS_ORIENTATION":1.2187477350234985},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":361,"AXIS_Y":719,"AXIS_PRESSURE":0.83203125,"AXIS_SIZE":0.03087143413722515,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":75,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":75,"AXIS_ORIENTATION":1.1489516496658325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":271,"AXIS_Y":603,"AXIS_PRESSURE":0.234375,"AXIS_SIZE":0.017389604821801186,"AXIS_TOUCH_MAJOR":60,"AXIS_TOUCH_MINOR":29,"AXIS_TOOL_MAJOR":60,"AXIS_TOOL_MINOR":29,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]},
+ {"action":"UP","axes":{"AXIS_X":271,"AXIS_Y":603,"AXIS_PRESSURE":0.234375,"AXIS_SIZE":0.017389604821801186,"AXIS_TOUCH_MAJOR":60,"AXIS_TOUCH_MINOR":29,"AXIS_TOOL_MAJOR":60,"AXIS_TOOL_MINOR":29,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]}
+ ]
+ }
+]
diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
new file mode 100644
index 0000000..072341d
--- /dev/null
+++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2024 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.hardware.input
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.os.Handler
+import android.os.IBinder
+import android.os.test.TestLooper
+import android.platform.test.annotations.Presubmit
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.KeyEvent
+import androidx.test.core.app.ApplicationProvider
+import com.android.server.testutils.any
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnitRunner
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import kotlin.test.fail
+
+/**
+ * Tests for [InputManager.KeyGestureEventHandler].
+ *
+ * Build/Install/Run:
+ * atest InputTests:KeyGestureEventHandlerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner::class)
+class KeyGestureEventHandlerTest {
+
+ companion object {
+ const val DEVICE_ID = 1
+ val HOME_GESTURE_EVENT = KeyGestureEvent.Builder()
+ .setDeviceId(DEVICE_ID)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
+ val BACK_GESTURE_EVENT = KeyGestureEvent.Builder()
+ .setDeviceId(DEVICE_ID)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_DEL))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build()
+ }
+
+ @get:Rule
+ val rule = SetFlagsRule()
+
+ private val testLooper = TestLooper()
+ private var registeredListener: IKeyGestureHandler? = null
+ private lateinit var context: Context
+ private lateinit var inputManager: InputManager
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
+
+ @Mock
+ private lateinit var iInputManagerMock: IInputManager
+
+ @Before
+ fun setUp() {
+ context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock)
+ inputManager = InputManager(context)
+ `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
+ .thenReturn(inputManager)
+
+ // Handle key gesture handler registration.
+ doAnswer {
+ val listener = it.getArgument(0) as IKeyGestureHandler
+ if (registeredListener != null &&
+ registeredListener!!.asBinder() != listener.asBinder()) {
+ // There can only be one registered key gesture handler per process.
+ fail("Trying to register a new listener when one already exists")
+ }
+ registeredListener = listener
+ null
+ }.`when`(iInputManagerMock).registerKeyGestureHandler(any())
+
+ // Handle key gesture handler being unregistered.
+ doAnswer {
+ val listener = it.getArgument(0) as IKeyGestureHandler
+ if (registeredListener == null ||
+ registeredListener!!.asBinder() != listener.asBinder()) {
+ fail("Trying to unregister a listener that is not registered")
+ }
+ registeredListener = null
+ null
+ }.`when`(iInputManagerMock).unregisterKeyGestureHandler(any())
+ }
+
+ @After
+ fun tearDown() {
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
+ }
+
+ private fun handleKeyGestureEvent(event: KeyGestureEvent) {
+ val eventToSend = AidlKeyGestureEvent()
+ eventToSend.deviceId = event.deviceId
+ eventToSend.keycodes = event.keycodes
+ eventToSend.modifierState = event.modifierState
+ eventToSend.gestureType = event.keyGestureType
+ eventToSend.action = event.action
+ eventToSend.displayId = event.displayId
+ eventToSend.flags = event.flags
+ registeredListener!!.handleKeyGesture(eventToSend, null)
+ }
+
+ @Test
+ fun testHandlerHasCorrectGestureNotified() {
+ var callbackCount = 0
+
+ // Add a key gesture event listener
+ inputManager.registerKeyGestureEventHandler(KeyGestureHandler { event, _ ->
+ assertEquals(HOME_GESTURE_EVENT, event)
+ callbackCount++
+ true
+ })
+
+ // Request handling for key gesture event will notify the handler.
+ handleKeyGestureEvent(HOME_GESTURE_EVENT)
+ assertEquals(1, callbackCount)
+ }
+
+ @Test
+ fun testAddingHandlersRegistersInternalCallbackHandler() {
+ // Set up two callbacks.
+ val callback1 = KeyGestureHandler { _, _ -> false }
+ val callback2 = KeyGestureHandler { _, _ -> false }
+
+ assertNull(registeredListener)
+
+ // Adding the handler should register the callback with InputManagerService.
+ inputManager.registerKeyGestureEventHandler(callback1)
+ assertNotNull(registeredListener)
+
+ // Adding another handler should not register new internal listener.
+ val currListener = registeredListener
+ inputManager.registerKeyGestureEventHandler(callback2)
+ assertEquals(currListener, registeredListener)
+ }
+
+ @Test
+ fun testRemovingHandlersUnregistersInternalCallbackHandler() {
+ // Set up two callbacks.
+ val callback1 = KeyGestureHandler { _, _ -> false }
+ val callback2 = KeyGestureHandler { _, _ -> false }
+
+ inputManager.registerKeyGestureEventHandler(callback1)
+ inputManager.registerKeyGestureEventHandler(callback2)
+
+ // Only removing all handlers should remove the internal callback
+ inputManager.unregisterKeyGestureEventHandler(callback1)
+ assertNotNull(registeredListener)
+ inputManager.unregisterKeyGestureEventHandler(callback2)
+ assertNull(registeredListener)
+ }
+
+ @Test
+ fun testMultipleHandlers() {
+ // Set up two callbacks.
+ var callbackCount1 = 0
+ var callbackCount2 = 0
+ // Handler 1 captures all home gestures
+ val callback1 = KeyGestureHandler { event, _ ->
+ callbackCount1++
+ event.keyGestureType == KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+ }
+ // Handler 2 captures all gestures
+ val callback2 = KeyGestureHandler { _, _ ->
+ callbackCount2++
+ true
+ }
+
+ // Add both key gesture event handlers
+ inputManager.registerKeyGestureEventHandler(callback1)
+ inputManager.registerKeyGestureEventHandler(callback2)
+
+ // Request handling for key gesture event, should notify callbacks in order. So, only the
+ // first handler should receive a callback since it captures the event.
+ handleKeyGestureEvent(HOME_GESTURE_EVENT)
+ assertEquals(1, callbackCount1)
+ assertEquals(0, callbackCount2)
+
+ // Second handler should receive the event since the first handler doesn't capture the event
+ handleKeyGestureEvent(BACK_GESTURE_EVENT)
+ assertEquals(2, callbackCount1)
+ assertEquals(1, callbackCount2)
+
+ inputManager.unregisterKeyGestureEventHandler(callback1)
+ // Request handling for key gesture event, should still trigger callback2 but not callback1.
+ handleKeyGestureEvent(HOME_GESTURE_EVENT)
+ assertEquals(2, callbackCount1)
+ assertEquals(2, callbackCount2)
+ }
+
+ inner class KeyGestureHandler(
+ private var handler: (event: KeyGestureEvent, token: IBinder?) -> Boolean
+ ) : InputManager.KeyGestureEventHandler {
+
+ override fun handleKeyGestureEvent(
+ event: KeyGestureEvent,
+ focusedToken: IBinder?
+ ): Boolean {
+ return handler(event, focusedToken)
+ }
+
+ override fun isKeyGestureSupported(gestureType: Int): Boolean {
+ return true
+ }
+ }
+}
diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt
index 14aac66..ca9de60 100644
--- a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt
+++ b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt
@@ -53,12 +53,12 @@
companion object {
const val DEVICE_ID = 1
- val HOME_GESTURE_EVENT = KeyGestureEvent(
- DEVICE_ID,
- intArrayOf(KeyEvent.KEYCODE_H),
- KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_HOME
- )
+ val HOME_GESTURE_EVENT = KeyGestureEvent.Builder()
+ .setDeviceId(DEVICE_ID)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
}
@get:Rule
@@ -114,12 +114,15 @@
}
private fun notifyKeyGestureEvent(event: KeyGestureEvent) {
- registeredListener!!.onKeyGestureEvent(
- event.deviceId,
- event.keycodes,
- event.modifierState,
- event.keyGestureType
- )
+ val eventToSend = AidlKeyGestureEvent()
+ eventToSend.deviceId = event.deviceId
+ eventToSend.keycodes = event.keycodes
+ eventToSend.modifierState = event.modifierState
+ eventToSend.gestureType = event.keyGestureType
+ eventToSend.action = event.action
+ eventToSend.displayId = event.displayId
+ eventToSend.flags = event.flags
+ registeredListener!!.onKeyGestureEvent(eventToSend)
}
@Test
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 3f611e0..e126797 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -18,18 +18,28 @@
import android.content.Context
import android.content.ContextWrapper
+import android.hardware.input.IInputManager
+import android.hardware.input.AidlKeyGestureEvent
import android.hardware.input.IKeyGestureEventListener
+import android.hardware.input.IKeyGestureHandler
+import android.hardware.input.InputManager
+import android.hardware.input.InputManagerGlobal
import android.hardware.input.KeyGestureEvent
+import android.os.IBinder
+import android.os.Process
+import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
+import android.view.InputDevice
import android.view.KeyEvent
import androidx.test.core.app.ApplicationProvider
+import com.android.internal.util.FrameworkStatsLog
+import com.android.modules.utils.testing.ExtendedMockitoRule
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.junit.MockitoJUnit
/**
* Tests for {@link KeyGestureController}.
@@ -41,26 +51,55 @@
class KeyGestureControllerTests {
companion object {
- val DEVICE_ID = 1
- val HOME_GESTURE_EVENT = KeyGestureEvent(
- DEVICE_ID,
- intArrayOf(KeyEvent.KEYCODE_H),
- KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_HOME
- )
+ const val DEVICE_ID = 1
+ val HOME_GESTURE_COMPLETE_EVENT = KeyGestureEvent.Builder()
+ .setDeviceId(DEVICE_ID)
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ .build()
}
- @get:Rule
- val rule = MockitoJUnit.rule()!!
+ @JvmField
+ @Rule
+ val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
+ .mockStatic(FrameworkStatsLog::class.java).build()!!
+ @Mock
+ private lateinit var iInputManager: IInputManager
+
+ private var currentPid = 0
private lateinit var keyGestureController: KeyGestureController
private lateinit var context: Context
- private var lastEvent: KeyGestureEvent? = null
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
+ private lateinit var testLooper: TestLooper
+ private var events = mutableListOf<KeyGestureEvent>()
@Before
fun setup() {
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
- keyGestureController = KeyGestureController()
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
+ setupInputDevices()
+ testLooper = TestLooper()
+ currentPid = Process.myPid()
+ keyGestureController = KeyGestureController(context, testLooper.looper)
+ }
+
+ private fun setupInputDevices() {
+ val inputManager = InputManager(context)
+ Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
+ .thenReturn(inputManager)
+
+ val keyboardDevice = InputDevice.Builder().setId(DEVICE_ID).build()
+ Mockito.`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID))
+ Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice)
+ }
+
+ private fun notifyHomeGestureCompleted() {
+ keyGestureController.notifyKeyGestureCompleted(DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H),
+ KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
}
@Test
@@ -69,28 +108,97 @@
// Register key gesture event listener
keyGestureController.registerKeyGestureEventListener(listener, 0)
- keyGestureController.onKeyGestureEvent(HOME_GESTURE_EVENT)
+ notifyHomeGestureCompleted()
+ testLooper.dispatchAll()
assertEquals(
- "Listener should get callback on key gesture event",
- HOME_GESTURE_EVENT,
- lastEvent!!
+ "Listener should get callbacks on key gesture event completed",
+ 1,
+ events.size
+ )
+ assertEquals(
+ "Listener should get callback for key gesture complete event",
+ HOME_GESTURE_COMPLETE_EVENT,
+ events[0]
)
// Unregister listener
- lastEvent = null
+ events.clear()
keyGestureController.unregisterKeyGestureEventListener(listener, 0)
- keyGestureController.onKeyGestureEvent(HOME_GESTURE_EVENT)
- assertNull("Listener should not get callback after being unregistered", lastEvent)
+ notifyHomeGestureCompleted()
+ testLooper.dispatchAll()
+ assertEquals(
+ "Listener should not get callback after being unregistered",
+ 0,
+ events.size
+ )
+ }
+
+ @Test
+ fun testKeyGestureEvent_multipleGestureHandlers() {
+ // Set up two callbacks.
+ var callbackCount1 = 0
+ var callbackCount2 = 0
+ var selfCallback = 0
+ val externalHandler1 = KeyGestureHandler { _, _ ->
+ callbackCount1++;
+ true
+ }
+ val externalHandler2 = KeyGestureHandler { _, _ ->
+ callbackCount2++;
+ true
+ }
+ val selfHandler = KeyGestureHandler { _, _ ->
+ selfCallback++;
+ false
+ }
+
+ // Register key gesture handler: External process (last in priority)
+ keyGestureController.registerKeyGestureHandler(externalHandler1, currentPid + 1)
+
+ // Register key gesture handler: External process (second in priority)
+ keyGestureController.registerKeyGestureHandler(externalHandler2, currentPid - 1)
+
+ // Register key gesture handler: Self process (first in priority)
+ keyGestureController.registerKeyGestureHandler(selfHandler, currentPid)
+
+ keyGestureController.handleKeyGesture(/* deviceId = */ 0, intArrayOf(KeyEvent.KEYCODE_HOME),
+ /* modifierState = */ 0, KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, /* displayId */ 0,
+ /* focusedToken = */ null, /* flags = */ 0
+ )
+
+ assertEquals(
+ "Self handler should get callbacks first",
+ 1,
+ selfCallback
+ )
+ assertEquals(
+ "Higher priority handler should get callbacks first",
+ 1,
+ callbackCount2
+ )
+ assertEquals(
+ "Lower priority handler should not get callbacks if already handled",
+ 0,
+ callbackCount1
+ )
}
inner class KeyGestureEventListener : IKeyGestureEventListener.Stub() {
- override fun onKeyGestureEvent(
- deviceId: Int,
- keycodes: IntArray,
- modifierState: Int,
- gestureType: Int
- ) {
- lastEvent = KeyGestureEvent(deviceId, keycodes, modifierState, gestureType)
+ override fun onKeyGestureEvent(event: AidlKeyGestureEvent) {
+ events.add(KeyGestureEvent(event))
+ }
+ }
+
+ inner class KeyGestureHandler(
+ private var handler: (event: AidlKeyGestureEvent, token: IBinder?) -> Boolean
+ ) : IKeyGestureHandler.Stub() {
+ override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean {
+ return handler(event, token)
+ }
+
+ override fun isKeyGestureSupported(gestureType: Int): Boolean {
+ return true
}
}
}
\ No newline at end of file
diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
index 99e04cc..0719686 100644
--- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
+++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
@@ -85,8 +85,8 @@
when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
mTouchpadDebugView = new TouchpadDebugView(mTestableContext, TOUCHPAD_DEVICE_ID,
- new TouchpadHardwareProperties.Builder(500f, 500f, 500f,
- 500f, 0f, 0f, -5f, 5f, (short) 10, true,
+ new TouchpadHardwareProperties.Builder(0f, 0f, 500f,
+ 500f, 45f, 47f, -4f, 5f, (short) 10, true,
true).build());
mTouchpadDebugView.measure(
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index d32cedb..cd6ab30 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -166,12 +166,12 @@
val displayManager =
instrumentation.context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val display = displayManager.getDisplay(obj.getDisplayId())
- val touchScreen = UinputTouchScreen(instrumentation, display)
-
val rect: Rect = obj.visibleBounds
- val pointer = touchScreen.touchDown(rect.centerX(), rect.centerY())
- pointer.lift()
- touchScreen.close()
+ UinputTouchScreen(instrumentation, display).use { touchScreen ->
+ touchScreen
+ .touchDown(rect.centerX(), rect.centerY())
+ .lift()
+ }
}
private fun triggerAnr() {
diff --git a/tests/Input/src/com/android/test/input/CaptureEventActivity.kt b/tests/Input/src/com/android/test/input/CaptureEventActivity.kt
new file mode 100644
index 0000000..d54e3470
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/CaptureEventActivity.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2024 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.test.input
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.InputEvent
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertNull
+
+class CaptureEventActivity : Activity() {
+ private val events = LinkedBlockingQueue<InputEvent>()
+ var shouldHandleKeyEvents = true
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // Set the fixed orientation if requested
+ if (intent.hasExtra(EXTRA_FIXED_ORIENTATION)) {
+ val orientation = intent.getIntExtra(EXTRA_FIXED_ORIENTATION, 0)
+ setRequestedOrientation(orientation)
+ }
+
+ // Set the flag if requested
+ if (intent.hasExtra(EXTRA_WINDOW_FLAGS)) {
+ val flags = intent.getIntExtra(EXTRA_WINDOW_FLAGS, 0)
+ window.addFlags(flags)
+ }
+ }
+
+ override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
+ events.add(KeyEvent(event))
+ return shouldHandleKeyEvents
+ }
+
+ override fun dispatchTrackballEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ fun getInputEvent(): InputEvent? {
+ return events.poll(5, TimeUnit.SECONDS)
+ }
+
+ fun hasReceivedEvents(): Boolean {
+ return !events.isEmpty()
+ }
+
+ fun assertNoEvents() {
+ val event = events.poll(100, TimeUnit.MILLISECONDS)
+ assertNull("Expected no events, but received $event", event)
+ }
+
+ companion object {
+ const val EXTRA_FIXED_ORIENTATION = "fixed_orientation"
+ const val EXTRA_WINDOW_FLAGS = "window_flags"
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
new file mode 100644
index 0000000..aa73c39
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2024 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.test.input
+
+import android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY
+import android.app.Instrumentation
+import android.cts.input.EventVerifier
+import android.graphics.PointF
+import android.hardware.input.InputManager
+import android.os.ParcelFileDescriptor
+import android.util.Log
+import android.util.Size
+import android.view.InputEvent
+import android.view.MotionEvent
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.cts.input.BatchedEventSplitter
+import com.android.cts.input.InputJsonParser
+import com.android.cts.input.VirtualDisplayActivityScenario
+import com.android.cts.input.inputeventmatchers.isResampled
+import com.android.cts.input.inputeventmatchers.withButtonState
+import com.android.cts.input.inputeventmatchers.withHistorySize
+import com.android.cts.input.inputeventmatchers.withMotionAction
+import com.android.cts.input.inputeventmatchers.withPressure
+import com.android.cts.input.inputeventmatchers.withRawCoords
+import com.android.cts.input.inputeventmatchers.withSource
+import java.io.InputStream
+import junit.framework.Assert.fail
+import org.hamcrest.Matchers.allOf
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Integration tests for the input pipeline that replays recording taken from physical input devices
+ * at the evdev interface level, and makes assertions on the events that are received by a test app.
+ *
+ * These tests associate the playback input device with a virtual display to make these tests
+ * agnostic to the device form factor.
+ *
+ * New recordings can be taken using the `evemu-record` shell command.
+ */
+@RunWith(Parameterized::class)
+class UinputRecordingIntegrationTests {
+
+ companion object {
+ /**
+ * Add new test cases by adding a new [TestData] to the following list.
+ */
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data(): Iterable<Any> =
+ listOf(
+ TestData(
+ "GooglePixelTabletTouchscreen", R.raw.google_pixel_tablet_touchscreen,
+ R.raw.google_pixel_tablet_touchscreen_events, Size(1600, 2560),
+ vendorId = 0x0603, productId = 0x7806
+ ),
+ )
+
+ /**
+ * Use the debug mode to see the JSON-encoded received events in logcat.
+ */
+ const val DEBUG_RECEIVED_EVENTS = false
+
+ const val INPUT_DEVICE_SOURCE_ALL = -1
+ val TAG = UinputRecordingIntegrationTests::class.java.simpleName
+ }
+
+ class TestData(
+ val name: String,
+ val uinputRecordingResource: Int,
+ val expectedEventsResource: Int,
+ val displaySize: Size,
+ val vendorId: Int,
+ val productId: Int,
+ ) {
+ override fun toString(): String = name
+ }
+
+ private lateinit var instrumentation: Instrumentation
+ private lateinit var parser: InputJsonParser
+
+ @get:Rule
+ val testName = TestName()
+
+ @Parameterized.Parameter(0)
+ lateinit var testData: TestData
+
+ @Before
+ fun setUp() {
+ instrumentation = InstrumentationRegistry.getInstrumentation()
+ parser = InputJsonParser(instrumentation.context)
+ }
+
+ @Test
+ fun testEvemuRecording() {
+ VirtualDisplayActivityScenario.AutoClose<CaptureEventActivity>(
+ testName,
+ size = testData.displaySize
+ ).use { scenario ->
+ scenario.activity.window.decorView.requestUnbufferedDispatch(INPUT_DEVICE_SOURCE_ALL)
+
+ try {
+ instrumentation.uiAutomation.adoptShellPermissionIdentity(
+ ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
+ )
+
+ val inputPort = "uinput:1:${testData.vendorId}:${testData.productId}"
+ val inputManager =
+ instrumentation.context.getSystemService(InputManager::class.java)!!
+ try {
+ inputManager.addUniqueIdAssociationByPort(
+ inputPort,
+ scenario.virtualDisplay.display.uniqueId!!,
+ )
+
+ injectUinputEvents()
+
+ if (DEBUG_RECEIVED_EVENTS) {
+ printReceivedEventsToLogcat(scenario.activity)
+ fail("Test cannot pass in debug mode!")
+ }
+
+ val verifier =
+ EventVerifier(BatchedEventSplitter { scenario.activity.getInputEvent() })
+ verifyEvents(verifier)
+ scenario.activity.assertNoEvents()
+ } finally {
+ inputManager.removeUniqueIdAssociationByPort(inputPort)
+ }
+ } finally {
+ instrumentation.uiAutomation.dropShellPermissionIdentity()
+ }
+ }
+ }
+
+ private fun printReceivedEventsToLogcat(activity: CaptureEventActivity) {
+ val getNextEvent = BatchedEventSplitter { activity.getInputEvent() }
+ var receivedEvent: InputEvent? = getNextEvent()
+ while (receivedEvent != null) {
+ Log.d(TAG,
+ parser.encodeEvent(receivedEvent)?.toString()
+ ?: "(Failed to encode received event)"
+ )
+ receivedEvent = getNextEvent()
+ }
+ }
+
+ private fun injectUinputEvents() {
+ val fds = instrumentation.uiAutomation!!.executeShellCommandRw("uinput -")
+
+ ParcelFileDescriptor.AutoCloseOutputStream(fds[1]).use { stdIn ->
+ val inputStream: InputStream = instrumentation.context.resources.openRawResource(
+ testData.uinputRecordingResource,
+ )
+ stdIn.write(inputStream.readBytes())
+ }
+ }
+
+ private fun verifyEvents(verifier: EventVerifier) {
+ val uinputTestData = parser.getUinputTestData(testData.expectedEventsResource)
+ for (test in uinputTestData) {
+ for ((index, expectedEvent) in test.events.withIndex()) {
+ if (expectedEvent is MotionEvent) {
+ verifier.assertReceivedMotion(
+ allOf(
+ withMotionAction(expectedEvent.action),
+ withSource(expectedEvent.source),
+ withButtonState(expectedEvent.buttonState),
+ withRawCoords(PointF(expectedEvent.rawX, expectedEvent.rawY)),
+ withPressure(expectedEvent.pressure),
+ isResampled(false),
+ withHistorySize(0),
+ ),
+ "${test.name}: Expected event at index $index",
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index 2909e66..331a21a 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -44,7 +44,7 @@
"libstaticjvmtiagent",
],
libs: [
- "android.test.mock",
+ "android.test.mock.stubs.system",
],
certificate: "platform",
platform_apis: true,
diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp
index d80eaeb..1a08f99 100644
--- a/tests/permission/Android.bp
+++ b/tests/permission/Android.bp
@@ -25,3 +25,10 @@
platform_apis: true,
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "FrameworkPermissionTests_Presubmit",
+ base: "FrameworkPermissionTests",
+ test_suites: ["device-tests"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index ea77b8d..4920f7b4 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -5,6 +5,10 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+
+ // OWNER: g/ravenwood
+ // Bug component: 25698
+ default_team: "trendy_team_framework_backstage_power",
}
// Visibility only for ravenwood prototype uses.
diff --git a/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
index f5af99e..b79563f 100644
--- a/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
+++ b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
@@ -103,3 +103,26 @@
return fix.build()
}
+
+/**
+ * PermissionAnnotationDetector uses this method to determine whether a specific file should be
+ * checked for unannotated methods. Only files located in directories whose paths begin with one
+ * of these prefixes will be considered.
+ */
+fun isSystemServicePath(context: JavaContext): Boolean {
+ val systemServicePathPrefixes = setOf(
+ "frameworks/base/services",
+ "frameworks/base/apex",
+ "frameworks/opt/wear",
+ "packages/modules"
+ )
+
+ val filePath = context.file.path
+
+ // We perform `filePath.contains` instead of `filePath.startsWith` since getting the
+ // relative path of a source file is non-trivial. That is because `context.file.path`
+ // returns the path to where soong builds the file (i.e. /out/soong/...). Moreover, the
+ // logic to extract the relative path would need to consider several /out/soong/...
+ // locations patterns.
+ return systemServicePathPrefixes.any { filePath.contains(it) }
+}
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index 5c64697..af753e5 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -20,7 +20,6 @@
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
import com.google.android.lint.parcel.SaferParcelChecker
-import com.google.android.lint.aidl.PermissionAnnotationDetector
import com.google.auto.service.AutoService
@AutoService(IssueRegistry::class)
@@ -38,7 +37,6 @@
SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
// TODO: Currently crashes due to OOM issue
// PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
- PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
FeatureAutomotiveDetector.ISSUE,
diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/PermissionAnnotationDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/PermissionAnnotationDetectorTest.kt
deleted file mode 100644
index bce848a..0000000
--- a/tools/lint/framework/checks/src/test/java/com/google/android/lint/PermissionAnnotationDetectorTest.kt
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2023 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.google.android.lint.aidl
-
-import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestFile
-import com.android.tools.lint.checks.infrastructure.TestLintTask
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Issue
-
-@Suppress("UnstableApiUsage")
-class PermissionAnnotationDetectorTest : LintDetectorTest() {
- override fun getDetector(): Detector = PermissionAnnotationDetector()
-
- override fun getIssues(): List<Issue> = listOf(
- PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
- )
-
- override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
-
- /** No issue scenario */
-
- fun testDoesNotDetectIssuesInCorrectScenario() {
- lint().files(
- java(
- """
- public class Foo extends IFoo.Stub {
- @Override
- @android.annotation.EnforcePermission("android.Manifest.permission.READ_CONTACTS")
- public void testMethod() { }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- fun testMissingAnnotation() {
- lint().files(
- java(
- """
- public class Bar extends IBar.Stub {
- public void testMethod() { }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expect(
- """
- src/Bar.java:2: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
- public void testMethod() { }
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 1 errors, 0 warnings
- """
- )
- }
-
- fun testNoIssueWhenExtendingWithAnotherSubclass() {
- lint().files(
- java(
- """
- public class Foo extends IFoo.Stub {
- @Override
- @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethod() { }
- // not an AIDL method, just another method
- public void someRandomMethod() { }
- }
- """).indented(),
- java(
- """
- public class Baz extends Bar {
- @Override
- public void someRandomMethod() { }
- }
- """).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- /* Stubs */
-
- // A service with permission annotation on the method.
- private val interfaceIFoo: TestFile = java(
- """
- public interface IFoo extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IFoo {
- }
- @Override
- @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethod();
- @Override
- @android.annotation.RequiresNoPermission
- public void testMethodNoPermission();
- @Override
- @android.annotation.PermissionManuallyEnforced
- public void testMethodManual();
- }
- """
- ).indented()
-
- // A service with no permission annotation.
- private val interfaceIBar: TestFile = java(
- """
- public interface IBar extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IBar {
- }
- public void testMethod();
- }
- """
- ).indented()
-
- private val stubs = arrayOf(interfaceIFoo, interfaceIBar)
-}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
index 28eab8f..290e7be 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
@@ -20,6 +20,7 @@
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
import com.google.android.lint.aidl.EnforcePermissionDetector
+import com.google.android.lint.aidl.PermissionAnnotationDetector
import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
import com.google.auto.service.AutoService
@@ -31,6 +32,7 @@
EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION,
+ PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
)
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
index 8777712..675a59e 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
@@ -20,12 +20,8 @@
* The exemptAidlInterfaces set was generated by running ExemptAidlInterfacesGenerator on the
* entire source tree. To reproduce the results, run generate-exempt-aidl-interfaces.sh
* located in tools/lint/utils.
- *
- * TODO: b/363248121 - Use the exemptAidlInterfaces set inside PermissionAnnotationDetector when it
- * gets migrated to a global lint check.
*/
val exemptAidlInterfaces = setOf(
- "android.accessibilityservice.IAccessibilityServiceConnection",
"android.accessibilityservice.IBrailleDisplayConnection",
"android.accounts.IAccountAuthenticatorResponse",
"android.accounts.IAccountManager",
@@ -663,10 +659,6 @@
"android.uwb.IUwbOemExtensionCallback",
"android.uwb.IUwbRangingCallbacks",
"android.uwb.IUwbVendorUciCallback",
- "android.view.accessibility.IAccessibilityInteractionConnectionCallback",
- "android.view.accessibility.IAccessibilityManager",
- "android.view.accessibility.IMagnificationConnectionCallback",
- "android.view.accessibility.IRemoteMagnificationAnimationCallback",
"android.view.autofill.IAutoFillManager",
"android.view.autofill.IAutofillWindowPresenter",
"android.view.contentcapture.IContentCaptureManager",
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionAnnotationDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
similarity index 92%
rename from tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionAnnotationDetector.kt
rename to tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
index 6b50cfd..d44c271 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionAnnotationDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
@@ -43,8 +43,14 @@
interfaceName: String,
body: UBlockExpression
) {
+ if (!isSystemServicePath(context)) return
+
if (context.evaluator.isAbstract(node)) return
+ val fullyQualifiedInterfaceName =
+ getContainingAidlInterfaceQualified(context, node) ?: return
+ if (exemptAidlInterfaces.contains(fullyQualifiedInterfaceName)) return
+
if (AIDL_PERMISSION_ANNOTATIONS.any { node.hasAnnotation(it) }) return
context.report(
@@ -80,8 +86,7 @@
implementation = Implementation(
PermissionAnnotationDetector::class.java,
Scope.JAVA_FILE_SCOPE
- ),
- enabledByDefault = false
+ )
)
}
}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
new file mode 100644
index 0000000..92d0829
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2023 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.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class PermissionAnnotationDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector =
+ PermissionAnnotationDetector()
+
+ override fun getIssues(): List<Issue> = listOf(
+ PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
+ )
+
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ /** No issue scenario */
+
+ fun testDoesNotDetectIssuesInCorrectScenario() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Foo.java"),
+ """
+ package com.android.server;
+ public class Foo extends IFoo.Stub {
+ @Override
+ @android.annotation.EnforcePermission("android.Manifest.permission.READ_CONTACTS")
+ public void testMethod() { }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMissingAnnotation() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ public void testMethod() { }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expect(
+ """
+ src/frameworks/base/services/java/com/android/server/Bar.java:3: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
+ public void testMethod() { }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 1 errors, 0 warnings
+ """
+ )
+ }
+
+ fun testMissingAnnotationInIgnoredDirectory() {
+ lint()
+ .files(
+ java(
+ ignoredPath,
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ public void testMethod() { }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ // If this test fails, consider the following steps:
+ // 1. Pick the first entry (interface) from `exemptAidlInterfaces`.
+ // 2. Change `interfaceIExempted` to use that interface.
+ // 3. Change this test's class to extend the interface's Stub.
+ fun testMissingAnnotationAidlInterfaceExempted() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends android.accessibilityservice.IBrailleDisplayConnection.Stub {
+ public void testMethod() { }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMissingAnnotationAidlInterfaceAbstractMethod() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public abstract class Bar extends IBar.Stub {
+ public abstract void testMethod();
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testNoIssueWhenExtendingWithAnotherSubclass() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Foo.java"),
+ """
+ package com.android.server;
+ public class Foo extends IFoo.Stub {
+ @Override
+ @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void testMethod() { }
+ // not an AIDL method, just another method
+ public void someRandomMethod() { }
+ }
+ """
+ )
+ .indented(),
+ java(
+ createVisitedPath("Baz.java"),
+ """
+ package com.android.server;
+ public class Baz extends Bar {
+ @Override
+ public void someRandomMethod() { }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ /* Stubs */
+
+ // A service with permission annotation on the method.
+ private val interfaceIFoo: TestFile = java(
+ """
+ public interface IFoo extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IFoo {
+ }
+ @Override
+ @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void testMethod();
+ @Override
+ @android.annotation.RequiresNoPermission
+ public void testMethodNoPermission();
+ @Override
+ @android.annotation.PermissionManuallyEnforced
+ public void testMethodManual();
+ }
+ """
+ ).indented()
+
+ // A service with no permission annotation.
+ private val interfaceIBar: TestFile = java(
+ """
+ public interface IBar extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBar {
+ }
+ public void testMethod();
+ }
+ """
+ ).indented()
+
+ // A service whose AIDL Interface is exempted.
+ private val interfaceIExempted: TestFile = java(
+ """
+ package android.accessibilityservice;
+ public interface IBrailleDisplayConnection extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
+ }
+ public void testMethod();
+ }
+ """
+ ).indented()
+
+ private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
+
+ private fun createVisitedPath(filename: String) =
+ "src/frameworks/base/services/java/com/android/server/$filename"
+
+ private val ignoredPath = "src/test/pkg/TestClass.java"
+}
diff --git a/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt
index 6ad223c..57c2e5a 100644
--- a/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt
+++ b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt
@@ -33,12 +33,6 @@
*/
class ExemptAidlInterfacesGenerator : AidlImplementationDetector() {
private val targetExemptAidlInterfaceNames = mutableSetOf<String>()
- private val systemServicePathPrefixes = setOf(
- "frameworks/base/services",
- "frameworks/base/apex",
- "frameworks/opt/wear",
- "packages/modules"
- )
// We could've improved performance by visiting classes rather than methods, however, this lint
// check won't be run regularly, hence we've decided not to add extra overrides to
@@ -49,14 +43,7 @@
interfaceName: String,
body: UBlockExpression
) {
- val filePath = context.file.path
-
- // We perform `filePath.contains` instead of `filePath.startsWith` since getting the
- // relative path of a source file is non-trivial. That is because `context.file.path`
- // returns the path to where soong builds the file (i.e. /out/soong/...). Moreover, the
- // logic to extract the relative path would need to consider several /out/soong/...
- // locations patterns.
- if (systemServicePathPrefixes.none { filePath.contains(it) }) return
+ if (!isSystemServicePath(context)) return
val fullyQualifiedInterfaceName =
getContainingAidlInterfaceQualified(context, node) ?: return
diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp
index aca25eb..a9e6328 100644
--- a/tools/systemfeatures/Android.bp
+++ b/tools/systemfeatures/Android.bp
@@ -5,6 +5,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_system_performance",
}
java_library_host {
@@ -25,8 +26,6 @@
static_libs: ["systemfeatures-gen-lib"],
}
-// TODO(b/203143243): Add golden diff test for generated sources.
-// Functional runtime behavior is covered in systemfeatures-gen-tests.
genrule {
name: "systemfeatures-gen-tests-srcs",
cmd: "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwNoFeatures --readonly=false > $(location RwNoFeatures.java) && " +
@@ -42,11 +41,12 @@
tools: ["systemfeatures-gen-tool"],
}
+// Functional runtime behavior testing.
java_test_host {
name: "systemfeatures-gen-tests",
test_suites: ["general-tests"],
srcs: [
- "tests/**/*.java",
+ "tests/src/**/*.java",
":systemfeatures-gen-tests-srcs",
],
test_options: {
@@ -61,3 +61,33 @@
"truth",
],
}
+
+// Rename the goldens as they may be copied into the source tree, and we don't
+// need or want the usual `.java` linting (e.g., copyright checks).
+genrule {
+ name: "systemfeatures-gen-tests-golden-srcs",
+ cmd: "for f in $(in); do cp $$f $(genDir)/tests/gen/$$(basename $$f).gen; done",
+ srcs: [":systemfeatures-gen-tests-srcs"],
+ out: [
+ "tests/gen/RwNoFeatures.java.gen",
+ "tests/gen/RoNoFeatures.java.gen",
+ "tests/gen/RwFeatures.java.gen",
+ "tests/gen/RoFeatures.java.gen",
+ ],
+}
+
+// Golden output testing. Golden sources can be updated via:
+// $ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/tests/golden_test.sh --update
+sh_test_host {
+ name: "systemfeatures-gen-golden-tests",
+ src: "tests/golden_test.sh",
+ filename: "systemfeatures-gen-golden-tests.sh",
+ test_config: "tests/systemfeatures-gen-golden-tests.xml",
+ data: [
+ "tests/golden/**/*.java*",
+ ":systemfeatures-gen-tests-golden-srcs",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index e537ffc..5df453d 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -142,6 +142,10 @@
// TODO(b/203143243): Add validation of build vs runtime values to ensure consistency.
JavaFile.builder(outputClassName.packageName(), classBuilder.build())
+ .indent(" ")
+ .skipJavaLangImports(true)
+ .addFileComment("This file is auto-generated. DO NOT MODIFY.\n")
+ .addFileComment("Args: ${args.joinToString(" \\\n ")}")
.build()
.writeTo(System.out)
}
@@ -178,6 +182,7 @@
val methodBuilder =
MethodSpec.methodBuilder(methodName)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+ .addJavadoc("Check for ${feature.name}.\n\n@hide")
.returns(Boolean::class.java)
.addParameter(CONTEXT_CLASS, "context")
@@ -228,6 +233,7 @@
MethodSpec.methodBuilder("maybeHasFeature")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addAnnotation(ClassName.get("android.annotation", "Nullable"))
+ .addJavadoc("@hide")
.returns(Boolean::class.javaObjectType) // Use object type for nullability
.addParameter(String::class.java, "featureName")
.addParameter(Int::class.java, "version")
diff --git a/tools/systemfeatures/tests/golden/RoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
new file mode 100644
index 0000000..724639b
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
@@ -0,0 +1,88 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RoFeatures \
+// --readonly=true \
+// --feature=WATCH:1 \
+// --feature=WIFI:0 \
+// --feature=VULKAN:-1 \
+// --feature=AUTO: \
+// --feature-apis=WATCH,PC
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import com.android.aconfig.annotations.AssumeFalseForR8;
+import com.android.aconfig.annotations.AssumeTrueForR8;
+
+/**
+ * @hide
+ */
+public final class RoFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ @AssumeTrueForR8
+ public static boolean hasFeatureWatch(Context context) {
+ return true;
+ }
+
+ /**
+ * Check for FEATURE_PC.
+ *
+ * @hide
+ */
+ public static boolean hasFeaturePc(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_PC);
+ }
+
+ /**
+ * Check for FEATURE_WIFI.
+ *
+ * @hide
+ */
+ @AssumeTrueForR8
+ public static boolean hasFeatureWifi(Context context) {
+ return true;
+ }
+
+ /**
+ * Check for FEATURE_VULKAN.
+ *
+ * @hide
+ */
+ @AssumeFalseForR8
+ public static boolean hasFeatureVulkan(Context context) {
+ return false;
+ }
+
+ /**
+ * Check for FEATURE_AUTO.
+ *
+ * @hide
+ */
+ @AssumeFalseForR8
+ public static boolean hasFeatureAuto(Context context) {
+ return false;
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ switch (featureName) {
+ case PackageManager.FEATURE_WATCH: return 1 >= version;
+ case PackageManager.FEATURE_WIFI: return 0 >= version;
+ case PackageManager.FEATURE_VULKAN: return -1 >= version;
+ case PackageManager.FEATURE_AUTO: return false;
+ default: break;
+ }
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
new file mode 100644
index 0000000..59c5b4e
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
@@ -0,0 +1,35 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RoNoFeatures \
+// --readonly=true \
+// --feature-apis=WATCH
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * @hide
+ */
+public final class RoNoFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWatch(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WATCH);
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RwFeatures.java.gen b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
new file mode 100644
index 0000000..6f89759
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
@@ -0,0 +1,65 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RwFeatures \
+// --readonly=false \
+// --feature=WATCH:1 \
+// --feature=WIFI:0 \
+// --feature=VULKAN:-1 \
+// --feature=AUTO:
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * @hide
+ */
+public final class RwFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWatch(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WATCH);
+ }
+
+ /**
+ * Check for FEATURE_WIFI.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWifi(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WIFI);
+ }
+
+ /**
+ * Check for FEATURE_VULKAN.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureVulkan(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_VULKAN);
+ }
+
+ /**
+ * Check for FEATURE_AUTO.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureAuto(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_AUTO);
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
new file mode 100644
index 0000000..2111d56
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
@@ -0,0 +1,24 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RwNoFeatures \
+// --readonly=false
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+
+/**
+ * @hide
+ */
+public final class RwNoFeatures {
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden_test.sh b/tools/systemfeatures/tests/golden_test.sh
new file mode 100755
index 0000000..c249254
--- /dev/null
+++ b/tools/systemfeatures/tests/golden_test.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2024 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.
+
+set -e
+
+GEN_DIR="tests/gen"
+GOLDEN_DIR="tests/golden"
+
+if [[ $(basename $0) == "golden_test.sh" ]]; then
+ # We're running via command-line, so we need to:
+ # 1) manually update generated srcs
+ # 2) use absolute paths
+ if [ -z $ANDROID_BUILD_TOP ]; then
+ echo "You need to source and lunch before you can use this script directly."
+ exit 1
+ fi
+ GEN_DIR="$ANDROID_BUILD_TOP/out/soong/.intermediates/frameworks/base/tools/systemfeatures/systemfeatures-gen-tests-golden-srcs/gen/$GEN_DIR"
+ GOLDEN_DIR="$ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/$GOLDEN_DIR"
+ rm -rf "$GEN_DIR"
+ "$ANDROID_BUILD_TOP"/build/soong/soong_ui.bash --make-mode systemfeatures-gen-tests-golden-srcs
+fi
+
+if [[ "$1" == "--update" ]]; then
+ rm -rf "$GOLDEN_DIR"
+ cp -R "$GEN_DIR" "$GOLDEN_DIR"
+ echo "Updated golden test files."
+else
+ echo "Running diff from test output against golden test files..."
+ if diff -ruN "$GOLDEN_DIR" "$GEN_DIR" ; then
+ echo "No changes."
+ else
+ echo
+ echo "----------------------------------------------------------------------------------------"
+ echo "If changes look OK, run:"
+ echo " \$ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/tests/golden_test.sh --update"
+ echo "----------------------------------------------------------------------------------------"
+ exit 1
+ fi
+fi
diff --git a/tools/systemfeatures/tests/Context.java b/tools/systemfeatures/tests/src/Context.java
similarity index 100%
rename from tools/systemfeatures/tests/Context.java
rename to tools/systemfeatures/tests/src/Context.java
diff --git a/tools/systemfeatures/tests/PackageManager.java b/tools/systemfeatures/tests/src/PackageManager.java
similarity index 100%
rename from tools/systemfeatures/tests/PackageManager.java
rename to tools/systemfeatures/tests/src/PackageManager.java
diff --git a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
similarity index 100%
rename from tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java
rename to tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
diff --git a/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml b/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml
new file mode 100644
index 0000000..e3a5841
--- /dev/null
+++ b/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs systemfeatures-gen golden diff test">
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+ <option name="binary" value="systemfeatures-gen-golden-tests.sh"/>
+ </test>
+</configuration>