diff options
959 files changed, 20235 insertions, 7365 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index bd17d6d2ece5..0ca97898e936 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -25,6 +25,7 @@ aconfig_declarations_group { "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 @@ aconfig_declarations_group { "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 @@ java_defaults { 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 @@ java_aconfig_library { 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 258440f24084..5b9f2cbf2d0d 100644 --- a/Android.bp +++ b/Android.bp @@ -427,6 +427,7 @@ java_defaults { "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 237c747e3a6f..80cd86cf9a5b 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 @@ import org.junit.runner.RunWith; 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 @@ public class AdditionPerfTest { } @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 @@ public class AdditionPerfTest { } @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 @@ public class AdditionPerfTest { } @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 @@ public class AdditionPerfTest { } @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 @@ public class AdditionPerfTest { } @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 @@ public class AdditionPerfTest { } @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 @@ public class AdditionPerfTest { } @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 1222bc242564..2f6c37832d04 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 @@ import java.util.Arrays; 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 @@ public class ArrayCopyPerfTest { @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 @@ public class ArrayCopyPerfTest { @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 @@ public class ArrayCopyPerfTest { @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 3f95e3e44f84..d17add767257 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 @@ public class ArrayIterationPerfTest { } @Rule - public BenchmarkRule mBenchmarkRule = new BenchmarkRule(); + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); Foo[] mArray = new Foo[27]; { @@ -46,7 +46,7 @@ public class ArrayIterationPerfTest { } @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 @@ public class ArrayIterationPerfTest { } @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 @@ public class ArrayIterationPerfTest { } @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 1423a13b43dc..3a57db8f323f 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 @@ public class ArrayListIterationPerfTest { int mSplat; } @Rule - public BenchmarkRule mBenchmarkRule = new BenchmarkRule(); + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); ArrayList<Foo> mList = new ArrayList<Foo>(); { @@ -47,7 +47,7 @@ public class ArrayListIterationPerfTest { } @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 @@ public class ArrayListIterationPerfTest { } @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 02831055ff56..3fb3bc8c0ff2 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 @@ import java.math.BigInteger; @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 @@ public class BigIntegerPerfTest { // 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 @@ public class BigIntegerPerfTest { // 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 @@ public class BigIntegerPerfTest { // 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 @@ public class BigIntegerPerfTest { // 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 @@ public class BigIntegerPerfTest { // 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 @@ public class BigIntegerPerfTest { // 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 11ca73acd45b..2a1b5d1cc6ce 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 @@ import java.util.zip.ZipOutputStream; @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 @@ public final class BufferedZipFilePerfTest { @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 @@ public final class BufferedZipFilePerfTest { @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 0abe194b6fdb..5f599ea85eb4 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 @@ import org.junit.runner.RunWith; @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 @@ public class ClassLoaderResourcePerfTest { 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 @@ public class ClassLoaderResourcePerfTest { 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 52441d1d868e..ea249848daad 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 @@ import org.junit.runner.RunWith; @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 class ClonePerfTest { 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 class ClonePerfTest { 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 class ClonePerfTest { 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 @@ public class ClonePerfTest { @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 @@ public class ClonePerfTest { 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 @@ public class ClonePerfTest { 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 e6c5aca2c330..82247dcee772 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 @@ import java.util.Collection; @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 @@ public class DeepArrayOpsPerfTest { @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 @@ public class DeepArrayOpsPerfTest { @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 378137b417e9..0bebf04c6897 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 @@ import org.junit.runner.RunWith; @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 @@ public class FieldAccessPerfTest { @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 @@ public class FieldAccessPerfTest { @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 @@ public class FieldAccessPerfTest { @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 @@ public class FieldAccessPerfTest { @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 class FieldAccessPerfTest { 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 class FieldAccessPerfTest { 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 class FieldAccessPerfTest { 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 class FieldAccessPerfTest { 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 class FieldAccessPerfTest { 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 610e8e56c951..55c1027e1add 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 @@ import java.util.concurrent.ConcurrentHashMap; @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 @@ public class HashedCollectionsPerfTest { 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 class HashedCollectionsPerfTest { 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 class HashedCollectionsPerfTest { 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 class HashedCollectionsPerfTest { 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 40c07e05bbde..da60a7773528 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 @@ import org.junit.runner.RunWith; @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 @@ public class ImtConflictPerfTest { @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 e1d0bf2f9491..6d9d0c92ff25 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 @@ import org.junit.runner.RunWith; @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 class MethodInvocationPerfTest { } 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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 @@ public class MethodInvocationPerfTest { @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 c5e9d1e1d5e4..09b09771e9de 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 @@ import org.junit.runner.RunWith; @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 @@ public class MultiplicationPerfTest { @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 class MultiplicationPerfTest { 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 class MultiplicationPerfTest { 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 d073f9163f39..ba21ed33bdb2 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 @@ import java.lang.reflect.Field; @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 @@ public class ReferenceGetPerfTest { @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 @@ public class ReferenceGetPerfTest { @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 @@ public class ReferenceGetPerfTest { 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 af13773dd177..293752ee5dd1 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 @@ import java.util.concurrent.atomic.AtomicInteger; @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 @@ public class ReferencePerfTest { @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 @@ public class ReferencePerfTest { @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 @@ public class ReferencePerfTest { @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 @@ public class ReferencePerfTest { @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 @@ public class ReferencePerfTest { // 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 cf573fa6f250..528b751d1551 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 @@ import java.util.Random; @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 class SmallBigIntegerPerfTest { 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 d28154c76067..1f301acd1dc6 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 @@ import org.junit.runner.RunWith; @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 40a8db0c5903..4268325f8c64 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 @@ import org.junit.runner.RunWith; @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 @@ public class StringIterationPerfTest { @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 @@ public class StringIterationPerfTest { @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 @@ public class StringIterationPerfTest { @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 147ea50f3a3c..cb3d3acb337f 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 @@ import java.util.Map; @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 @@ public class VirtualVersusInterfacePerfTest { @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 bb1c298c67b2..5be8ee6e67e2 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 @@ import java.util.Random; @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 @@ public class XmlSerializePerfTest { 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 9360a25fc86a..a37b89ddf033 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 @@ import java.nio.charset.StandardCharsets; 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 @@ public class XmlSerializerPerfTest { @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 @@ public class XmlSerializerPerfTest { @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 @@ public class XmlSerializerPerfTest { @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 03f183a01d11..ed669beae1ce 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 @@ import java.util.zip.ZipOutputStream; @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 @@ public class ZipFilePerfTest { @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 36140611c978..d239a054fac7 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 @@ import java.util.zip.ZipOutputStream; @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 @@ public class ZipFileReadPerfTest { @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 8890f51fe5cd..487295c03c0e 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 @@ import java.lang.reflect.Method; @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 @@ public class AnnotatedElementPerfTest { @Test public void timeGetTypeAnnotations() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mType.getAnnotations(); } @@ -61,7 +60,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetFieldAnnotations() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mField.getAnnotations(); } @@ -69,7 +68,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetMethodAnnotations() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mMethod.getAnnotations(); } @@ -77,7 +76,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetParameterAnnotations() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mMethod.getParameterAnnotations(); } @@ -85,7 +84,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetTypeAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mType.getAnnotation(Marker.class); } @@ -93,7 +92,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetFieldAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mField.getAnnotation(Marker.class); } @@ -101,7 +100,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetMethodAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mMethod.getAnnotation(Marker.class); } @@ -109,7 +108,7 @@ public class AnnotatedElementPerfTest { @Test public void timeIsTypeAnnotationPresent() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mType.isAnnotationPresent(Marker.class); } @@ -117,7 +116,7 @@ public class AnnotatedElementPerfTest { @Test public void timeIsFieldAnnotationPresent() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mField.isAnnotationPresent(Marker.class); } @@ -125,7 +124,7 @@ public class AnnotatedElementPerfTest { @Test public void timeIsMethodAnnotationPresent() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mMethod.isAnnotationPresent(Marker.class); } @@ -135,7 +134,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetAllReturnsLargeAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasLargeAnnotation.class.getAnnotations(); } @@ -143,7 +142,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetAllReturnsSmallAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasSmallAnnotation.class.getAnnotations(); } @@ -151,7 +150,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetAllReturnsMarkerAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasMarkerAnnotation.class.getAnnotations(); } @@ -159,7 +158,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetAllReturnsNoAnnotation() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasNoAnnotations.class.getAnnotations(); } @@ -167,7 +166,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetAllReturnsThreeAnnotations() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasThreeAnnotations.class.getAnnotations(); } @@ -177,7 +176,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetAnnotationsOnSubclass() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { ExtendsHasThreeAnnotations.class.getAnnotations(); } @@ -185,7 +184,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetDeclaredAnnotationsOnSubclass() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { ExtendsHasThreeAnnotations.class.getDeclaredAnnotations(); } @@ -195,7 +194,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetDeclaredClasses() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { AnnotatedElementPerfTest.class.getDeclaredClasses(); } @@ -203,7 +202,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetDeclaringClass() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasSmallAnnotation.class.getDeclaringClass(); } @@ -212,7 +211,7 @@ public class AnnotatedElementPerfTest { @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 @@ public class AnnotatedElementPerfTest { @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 @@ public class AnnotatedElementPerfTest { @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 @@ public class AnnotatedElementPerfTest { @Test public void timeGetModifiers() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasSmallAnnotation.class.getModifiers(); } @@ -246,7 +245,7 @@ public class AnnotatedElementPerfTest { @Test public void timeGetSimpleName() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { HasSmallAnnotation.class.getSimpleName(); } @@ -255,7 +254,7 @@ public class AnnotatedElementPerfTest { @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 @@ public class AnnotatedElementPerfTest { @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 baab8602b265..adc5d8c2bb3e 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 @@ import java.text.DecimalFormat; @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 @@ public class BidiPerfTest { @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 @@ public class BidiPerfTest { @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 @@ public class BidiPerfTest { @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 @@ public class BidiPerfTest { @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 @@ public class BidiPerfTest { @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 @@ public class BidiPerfTest { @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 8a539f89d3ca..286d70339c5f 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 @@ import java.util.Random; @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 @@ public class BigIntegerPerfTest { 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 @@ public class BigIntegerPerfTest { 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 1b46ff4f433a..d6462024a380 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 @@ import java.util.Collection; @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 @@ public class BitSetPerfTest { @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 class BitSetPerfTest { 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 @@ public class BitSetPerfTest { @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 @@ public class BitSetPerfTest { @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 class BitSetPerfTest { 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 class BitSetPerfTest { 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 class BitSetPerfTest { 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 3c5e4fd159c8..b887f4033462 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 @@ import java.util.Locale; @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 @@ public final class BreakIteratorPerfTest { @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 @@ public final class BreakIteratorPerfTest { @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 6df67bccae06..e4eaf12e9dcb 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 @@ import java.util.Collection; @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 @@ public class BulkPerfTest { 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 f01ac0247908..42e3910aab4b 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 @@ import java.util.Collection; @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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { 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 @@ public class ByteBufferPerfTest { @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 @@ public class ByteBufferPerfTest { @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 8c318cd0a298..9ee927cfc353 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 @@ import java.util.Collection; @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 @@ public class ByteBufferScalarVersusVectorPerfTest { 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 class ByteBufferScalarVersusVectorPerfTest { 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 class ByteBufferScalarVersusVectorPerfTest { 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 12c1f8cca0ec..e4a4db739235 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 @@ import java.util.Collection; @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 class CharacterPerfTest { 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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 @@ public class CharacterPerfTest { @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 4dd890ad2a45..858c101fc33e 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 @@ import java.nio.charset.Charset; @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 @@ public class CharsetForNamePerfTest { @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 3a71ce9692bd..a2fb7d7f83d8 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 @@ import java.util.Collection; @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 @@ public class CharsetPerfTest { @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 @@ public class CharsetPerfTest { @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 @@ public class CharsetPerfTest { @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 @@ public class CharsetPerfTest { @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 6c30a163f519..2047444a7f52 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 @@ import java.nio.charset.Charset; @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 @@ public class CharsetUtf8PerfTest { } 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 dcdfd371e7f6..4ce8b41de403 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 @@ import java.util.zip.CRC32; @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 @@ public class ChecksumPerfTest { @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 class ChecksumPerfTest { 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 @@ public class ChecksumPerfTest { @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 6c175b191429..6a7ec1ad62e9 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 @@ import javax.crypto.spec.IvParameterSpec; @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 @@ public class CipherInputStreamPerfTest { @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 136822ec7002..238c028fa0cf 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 @@ import javax.crypto.spec.IvParameterSpec; @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 @@ public class CipherPerfTest { 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 @@ public class CipherPerfTest { 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 9efb7ce7c2d0..7e5566055fb4 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 @@ import java.util.Locale; @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 @@ public class CollatorPerfTest { @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 @@ public class CollatorPerfTest { @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 @@ public class CollatorPerfTest { @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 @@ public class CollatorPerfTest { @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 4e5ceaf12403..100798a7957b 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 @@ import java.util.Vector; @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 @@ public class CollectionsPerfTest { @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 @@ public class CollectionsPerfTest { @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 @@ public class CollectionsPerfTest { @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 @@ public class CollectionsPerfTest { @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 b0ccd9925d83..b6784a8d3867 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 @@ import java.util.Locale; @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 @@ public final class DateFormatPerfTest { @Test public void timeGetDateTimeInstance() throws Exception { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { DateFormat.getDateTimeInstance(); } @@ -58,7 +58,7 @@ public final class DateFormatPerfTest { @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 3a2f6fab5460..52f98738481f 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 @@ import java.util.Locale; @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 class DecimalFormatPerfTest { 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 class DecimalFormatPerfTest { 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 class DecimalFormatPerfTest { 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 @@ public class DecimalFormatPerfTest { @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 4bc550ebb9f1..610542061107 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 @@ import java.util.Locale; @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 597447bef90e..fae74a5e8620 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 @@ import java.nio.charset.Charset; @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 b17d0f4194d8..2915363786f3 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 @@ import java.net.UnknownHostException; @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 @@ public class DnsPerfTest { "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 4c8a8eaea8c6..dd7e5cc1057b 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 @@ import java.security.PrivilegedAction; @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 @@ public class DoPrivilegedPerfTest { @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 @@ public class DoPrivilegedPerfTest { @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 @@ public class DoPrivilegedPerfTest { @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 4ff65b197947..e034a47e79d2 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 @@ import org.junit.runner.RunWith; @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 @@ public class DoublePerfTest { @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 @@ public class DoublePerfTest { @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 @@ public class DoublePerfTest { @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 aacdcee13e8d..fe1b599cc5ad 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 @@ import java.util.List; @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 @@ public final class EqualsHashCodePerfTest { 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 final class EqualsHashCodePerfTest { 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 @@ public final class EqualsHashCodePerfTest { "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 9a6864ea5f66..ecbfc7169945 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 @@ import java.util.Locale; @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 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @Test public void timeNewDateFormatSymbols() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { new DateFormatSymbols(Locale.US); } @@ -100,7 +100,7 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @Test public void timeNewDecimalFormatSymbols() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { new DecimalFormatSymbols(Locale.US); } @@ -117,7 +117,7 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @Test public void timeNewNumberFormat() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { NumberFormat.getInstance(Locale.US); } @@ -134,7 +134,7 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @Test public void timeLongToString() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { Long.toString(1024L); } @@ -151,7 +151,7 @@ public class ExpensiveObjectsPerfTest { @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 @@ public class ExpensiveObjectsPerfTest { @Test public void timeNewSimpleDateFormat() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { new SimpleDateFormat(); } @@ -167,7 +167,7 @@ public class ExpensiveObjectsPerfTest { @Test public void timeNewGregorianCalendar() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { new GregorianCalendar(); } @@ -176,7 +176,7 @@ public class ExpensiveObjectsPerfTest { @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 cef7e8c739d7..0c14d64c27a9 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 @@ import java.io.File; @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 @@ public final class FilePerfTest { @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 645c02357970..7d7d83b3fdbf 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 @@ import org.junit.runner.RunWith; @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 @@ public class FloatPerfTest { @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 @@ public class FloatPerfTest { @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 @@ public class FloatPerfTest { @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 cf76137d5ec3..08dda5314eac 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 @@ import java.util.Locale; @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 class FormatterPerfTest { 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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 @@ public class FormatterPerfTest { @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 833575afe8dc..a09ad809a6a2 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 @@ import java.net.IDN; @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 @@ public class IdnPerfTest { @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 1c901c867fe7..be22814ef8f4 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 @@ import org.junit.runner.RunWith; @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 @@ public class IntConstantDivisionPerfTest { @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 @@ public class IntConstantDivisionPerfTest { @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 @@ public class IntConstantDivisionPerfTest { @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 @@ public class IntConstantDivisionPerfTest { @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 @@ public class IntConstantDivisionPerfTest { @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 class IntConstantDivisionPerfTest { 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 class IntConstantDivisionPerfTest { 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 3d3af4cdb04c..4337c903ecd6 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 @@ import org.junit.runner.RunWith; @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 @@ public class IntConstantMultiplicationPerfTest { @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 class IntConstantMultiplicationPerfTest { 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 class IntConstantMultiplicationPerfTest { 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 7c86633accdc..1b6c5026e1f6 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 @@ import org.junit.runner.RunWith; @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 @@ public class IntConstantRemainderPerfTest { @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 @@ public class IntConstantRemainderPerfTest { @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 @@ public class IntConstantRemainderPerfTest { @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 @@ public class IntConstantRemainderPerfTest { @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 class IntConstantRemainderPerfTest { 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 class IntConstantRemainderPerfTest { 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 e2a9dcc8f93d..170bb58c46ed 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 class IntegerPerfTest { 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 class IntegerPerfTest { 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 class IntegerPerfTest { 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 class IntegerPerfTest { 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 class IntegerPerfTest { 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 class IntegerPerfTest { 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 @@ public class IntegerPerfTest { "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 669bfbfb2b8d..0aa854ecfa80 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 @@ import org.junit.runner.RunWith; @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 @@ public class IntegralToStringPerfTest { @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 cda8512ad6af..9b3d7a044720 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 @@ import java.util.Collection; @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 @@ public class KeyPairGeneratorPerfTest { @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 8b062d390dbb..1a9e19aeb78d 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 @@ import java.util.Collection; @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 @@ public class LoopingBackwardsPerfTest { @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 @@ public class LoopingBackwardsPerfTest { @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 bcf556c26716..a8a704c09d6d 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 @@ import org.junit.runner.RunWith; @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 @@ public class MathPerfTest { @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 8325dae67797..6da9666db23b 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 @@ import java.util.Collection; @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 @@ public class MessageDigestPerfTest { @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 266d42cba6f0..060d18fb3de3 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 @@ import java.util.concurrent.atomic.AtomicInteger; @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 @@ public final class MutableIntPerfTest { @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 c2f84fb71405..7cb3b2283779 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 @@ import java.util.Locale; @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 cdf0911c74ab..272b45a3affe 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 @@ import java.util.Locale; @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 51f47bb60ac7..c3a09662fd1f 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 @@ import java.util.Random; @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 @@ public class PriorityQueuePerfTest { // 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 1f20cae0c162..2ac56bed1910 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 @@ import java.lang.reflect.Method; @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 @@ public final class PropertyAccessPerfTest { @Test public void timeDirectSetter() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mView.mSetX(0.1f); } @@ -58,7 +58,7 @@ public final class PropertyAccessPerfTest { @Test public void timeDirectFieldSet() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mView.mX = 0.1f; } @@ -66,7 +66,7 @@ public final class PropertyAccessPerfTest { @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 @@ public final class PropertyAccessPerfTest { @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 @@ public final class PropertyAccessPerfTest { @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 @@ public final class PropertyAccessPerfTest { @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 @@ public final class PropertyAccessPerfTest { @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 @@ public final class PropertyAccessPerfTest { @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 @@ public final class PropertyAccessPerfTest { @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 0c16265fa6f7..7ad0141c8471 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 @@ import javax.crypto.Cipher; @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 @@ public class ProviderPerfTest { @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 5f1bfc29129e..c7b6cb5a190c 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 @@ import java.util.Random; @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 @@ public class RandomPerfTest { @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 @@ public class RandomPerfTest { @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 @@ public class RandomPerfTest { @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 008c94c52492..44e5f227b00a 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 @@ import org.junit.runner.RunWith; @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 @@ public class RealToStringPerfTest { @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 45b623d740ee..6e00b10838a6 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 @@ import java.lang.reflect.Method; @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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @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 class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { 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 class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { 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 class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @Test public void timeRegularConstructor() throws Exception { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { new C(); } @@ -206,7 +206,7 @@ public class ReflectionPerfTest { @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 class ReflectionPerfTest { 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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @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 @@ public class ReflectionPerfTest { @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 da69f9fc9fcf..5a9b5c36d0d3 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 @@ import javax.net.ssl.SSLSocket; @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 9f2c312f33ee..6d48cf26c971 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 @@ import javax.net.ssl.SSLSocketFactory; @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 7c60c05ef679..86416291f26d 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 @@ import java.util.regex.Pattern; @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 @@ public final class SchemePrefixPerfTest { @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 181298305cb5..afd1191a07fa 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 @@ import java.util.ArrayList; @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 class SerializationPerfTest { 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 @@ public class SerializationPerfTest { 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 @@ public class SerializationPerfTest { 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 34e9bfb84813..6c261332aa99 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 @@ import java.util.Map; @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 @@ public class SignaturePerfTest { @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 @@ public class SignaturePerfTest { @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 2fe67985d205..274b51f6fae4 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 @@ import java.util.Date; @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 @@ public class SimpleDateFormatPerfTest { @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 @@ public class SimpleDateFormatPerfTest { @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 @@ public class SimpleDateFormatPerfTest { @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 @@ public class SimpleDateFormatPerfTest { @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 @@ public class SimpleDateFormatPerfTest { @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 @@ public class SimpleDateFormatPerfTest { @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 @@ public class SimpleDateFormatPerfTest { @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 fbe3cefff776..b4c427beac65 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 @@ import org.junit.runner.RunWith; @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 @@ public class StrictMathPerfTest { @Test public void timeAbsD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.abs(mDouble); } @@ -82,7 +82,7 @@ public class StrictMathPerfTest { @Test public void timeAbsF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.abs(mFloat); } @@ -90,7 +90,7 @@ public class StrictMathPerfTest { @Test public void timeAbsI() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.abs(mInt); } @@ -98,7 +98,7 @@ public class StrictMathPerfTest { @Test public void timeAbsL() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.abs(mLong); } @@ -106,7 +106,7 @@ public class StrictMathPerfTest { @Test public void timeAcos() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.acos(mDouble); } @@ -114,7 +114,7 @@ public class StrictMathPerfTest { @Test public void timeAsin() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.asin(mDouble); } @@ -122,7 +122,7 @@ public class StrictMathPerfTest { @Test public void timeAtan() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.atan(mDouble); } @@ -130,7 +130,7 @@ public class StrictMathPerfTest { @Test public void timeAtan2() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.atan2(3, 4); } @@ -138,7 +138,7 @@ public class StrictMathPerfTest { @Test public void timeCbrt() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.cbrt(mDouble); } @@ -146,7 +146,7 @@ public class StrictMathPerfTest { @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 @@ public class StrictMathPerfTest { @Test public void timeCopySignD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.copySign(mDouble, mDouble); } @@ -164,7 +164,7 @@ public class StrictMathPerfTest { @Test public void timeCopySignF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.copySign(mFloat, mFloat); } @@ -172,7 +172,7 @@ public class StrictMathPerfTest { @Test public void timeCos() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.cos(mDouble); } @@ -180,7 +180,7 @@ public class StrictMathPerfTest { @Test public void timeCosh() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.cosh(mDouble); } @@ -188,7 +188,7 @@ public class StrictMathPerfTest { @Test public void timeExp() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.exp(mDouble); } @@ -196,7 +196,7 @@ public class StrictMathPerfTest { @Test public void timeExpm1() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.expm1(mDouble); } @@ -204,7 +204,7 @@ public class StrictMathPerfTest { @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 @@ public class StrictMathPerfTest { @Test public void timeGetExponentD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.getExponent(mDouble); } @@ -222,7 +222,7 @@ public class StrictMathPerfTest { @Test public void timeGetExponentF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.getExponent(mFloat); } @@ -230,7 +230,7 @@ public class StrictMathPerfTest { @Test public void timeHypot() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.hypot(mDouble, mDouble); } @@ -238,7 +238,7 @@ public class StrictMathPerfTest { @Test public void timeIEEEremainder() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.IEEEremainder(mDouble, mDouble); } @@ -246,7 +246,7 @@ public class StrictMathPerfTest { @Test public void timeLog() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.log(mDouble); } @@ -254,7 +254,7 @@ public class StrictMathPerfTest { @Test public void timeLog10() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.log10(mDouble); } @@ -262,7 +262,7 @@ public class StrictMathPerfTest { @Test public void timeLog1p() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.log1p(mDouble); } @@ -270,7 +270,7 @@ public class StrictMathPerfTest { @Test public void timeMaxD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.max(mDouble, mDouble); } @@ -278,7 +278,7 @@ public class StrictMathPerfTest { @Test public void timeMaxF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.max(mFloat, mFloat); } @@ -286,7 +286,7 @@ public class StrictMathPerfTest { @Test public void timeMaxI() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.max(mInt, mInt); } @@ -294,7 +294,7 @@ public class StrictMathPerfTest { @Test public void timeMaxL() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.max(mLong, mLong); } @@ -302,7 +302,7 @@ public class StrictMathPerfTest { @Test public void timeMinD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.min(mDouble, mDouble); } @@ -310,7 +310,7 @@ public class StrictMathPerfTest { @Test public void timeMinF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.min(mFloat, mFloat); } @@ -318,7 +318,7 @@ public class StrictMathPerfTest { @Test public void timeMinI() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.min(mInt, mInt); } @@ -326,7 +326,7 @@ public class StrictMathPerfTest { @Test public void timeMinL() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.min(mLong, mLong); } @@ -334,7 +334,7 @@ public class StrictMathPerfTest { @Test public void timeNextAfterD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.nextAfter(mDouble, mDouble); } @@ -342,7 +342,7 @@ public class StrictMathPerfTest { @Test public void timeNextAfterF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.nextAfter(mFloat, mFloat); } @@ -350,7 +350,7 @@ public class StrictMathPerfTest { @Test public void timeNextUpD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.nextUp(mDouble); } @@ -358,7 +358,7 @@ public class StrictMathPerfTest { @Test public void timeNextUpF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.nextUp(mFloat); } @@ -366,7 +366,7 @@ public class StrictMathPerfTest { @Test public void timePow() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.pow(mDouble, mDouble); } @@ -374,7 +374,7 @@ public class StrictMathPerfTest { @Test public void timeRandom() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.random(); } @@ -382,7 +382,7 @@ public class StrictMathPerfTest { @Test public void timeRint() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.rint(mDouble); } @@ -390,7 +390,7 @@ public class StrictMathPerfTest { @Test public void timeRoundD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.round(mDouble); } @@ -398,7 +398,7 @@ public class StrictMathPerfTest { @Test public void timeRoundF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.round(mFloat); } @@ -406,7 +406,7 @@ public class StrictMathPerfTest { @Test public void timeScalbD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.scalb(mDouble, 5); } @@ -414,7 +414,7 @@ public class StrictMathPerfTest { @Test public void timeScalbF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.scalb(mFloat, 5); } @@ -422,7 +422,7 @@ public class StrictMathPerfTest { @Test public void timeSignumD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.signum(mDouble); } @@ -430,7 +430,7 @@ public class StrictMathPerfTest { @Test public void timeSignumF() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.signum(mFloat); } @@ -438,7 +438,7 @@ public class StrictMathPerfTest { @Test public void timeSin() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.sin(mDouble); } @@ -446,7 +446,7 @@ public class StrictMathPerfTest { @Test public void timeSinh() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.sinh(mDouble); } @@ -454,7 +454,7 @@ public class StrictMathPerfTest { @Test public void timeSqrt() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.sqrt(mDouble); } @@ -462,7 +462,7 @@ public class StrictMathPerfTest { @Test public void timeTan() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.tan(mDouble); } @@ -470,7 +470,7 @@ public class StrictMathPerfTest { @Test public void timeTanh() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.tanh(mDouble); } @@ -478,7 +478,7 @@ public class StrictMathPerfTest { @Test public void timeToDegrees() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.toDegrees(mDouble); } @@ -486,7 +486,7 @@ public class StrictMathPerfTest { @Test public void timeToRadians() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.toRadians(mDouble); } @@ -494,7 +494,7 @@ public class StrictMathPerfTest { @Test public void timeUlpD() { - final BenchmarkState state = mBenchmarkRule.getState(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { StrictMath.ulp(mDouble); } @@ -502,7 +502,7 @@ public class StrictMathPerfTest { @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 0155154037df..2235cc5611a4 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 @@ import org.junit.runner.RunWith; @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { @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 @@ public class StringBuilderPerfTest { 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 @@ public class StringBuilderPerfTest { @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 55337452611b..9ab50005e62a 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 @@ import org.junit.runner.RunWith; @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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 @@ public class StringEqualsPerfTest { // 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 a5662b0a33bd..b1e749cc538c 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 @@ import org.junit.runner.RunWith; @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 @@ public class StringIsEmptyPerfTest { @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 @@ public class StringIsEmptyPerfTest { @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 @@ public class StringIsEmptyPerfTest { @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 41e64f2810c3..9e5759171a6f 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 @@ import org.junit.runner.RunWith; @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 2cd2a0976451..a80514c72e95 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 @@ import java.util.Collection; @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 @@ public class StringPerfTest { @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 219dccf6901b..78ae3952719b 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 @@ import java.util.Collection; @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 @@ public class StringReplaceAllPerfTest { @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 @@ public class StringReplaceAllPerfTest { @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 @@ public class StringReplaceAllPerfTest { @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 d6fef5ed84e7..73911c71c351 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 @@ import java.util.Collection; @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 @@ public class StringReplacePerfTest { @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 @@ public class StringReplacePerfTest { @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 @@ public class StringReplacePerfTest { @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 @@ public class StringReplacePerfTest { @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 @@ public class StringReplacePerfTest { @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 @@ public class StringReplacePerfTest { @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 9d0ec2f368c9..1539271c2b3c 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 @@ import java.util.regex.Pattern; @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 @@ public class StringSplitPerfTest { @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 @@ public class StringSplitPerfTest { @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 @@ public class StringSplitPerfTest { @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 @@ public class StringSplitPerfTest { @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 @@ public class StringSplitPerfTest { @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 11950b70ab3d..0d5e62b4268c 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 @@ import java.util.Collection; @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 @@ public class StringToBytesPerfTest { @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 @@ public class StringToBytesPerfTest { @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 @@ public class StringToBytesPerfTest { @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 4b27a16538ab..ecdf809f1610 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 @@ import java.util.Collection; @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 @@ public class StringToRealPerfTest { @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 @@ public class StringToRealPerfTest { @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 0ab012dc2871..2b2a6b5727de 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 @@ import org.junit.runner.RunWith; @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 @@ public class ThreadLocalPerfTest { @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 ddf410eccbcb..6eb8fccf5b2a 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 @@ import java.util.TimeZone; @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 @@ public class TimeZonePerfTest { @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 @@ public class TimeZonePerfTest { @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 @@ public class TimeZonePerfTest { // 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 @@ public class TimeZonePerfTest { // 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 @@ public class TimeZonePerfTest { @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 a38763b6ffad..288c646ec67d 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 @@ import javax.xml.parsers.DocumentBuilderFactory; @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 @@ public final class XMLEntitiesPerfTest { @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 @@ public final class XMLEntitiesPerfTest { @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 4076c9d18e57..003c957d894f 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 @@ public class ReflectGetFieldLittleEndianIntPerfTest { @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 2c65dd4a90f3..4f216181d5e3 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 @@ public class ReflectGetFieldLittleEndianStringPerfTest { @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 dcd25db01f18..210014ad3f6e 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 @@ public class ReflectGetStaticFieldLittleEndianIntPerfTest { @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 c938a4cda5a0..22c68273bf12 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 @@ public class ReflectGetStaticFieldLittleEndianStringPerfTest { @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 618e1b5f5b41..5b391091253b 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 @@ public class ReflectSetFieldLittleEndianIntPerfTest { @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 8c2e3ca8d586..883e8a76586b 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 @@ public class ReflectSetFieldLittleEndianStringPerfTest { @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 e888cc68d471..50bc85c31280 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 @@ public class ReflectSetStaticFieldLittleEndianIntPerfTest { @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 7016611a1b1d..13fa2bf7d230 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 @@ public class ReflectSetStaticFieldLittleEndianStringPerfTest { @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 65c82cca87be..85c9bae9a9d9 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest { @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 a350b61da20b..2b8f430440f5 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest { @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 34f596eea6aa..246fa43d0dca 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTes @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 2216d7b2a507..d12ffae25c5e 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 @@ import java.lang.invoke.VarHandle; @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 bda551fd9069..5ced1157cb73 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeFieldLittleEndianIntPerfTest { @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 f4d7893a64c2..b955d506fe85 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeFieldLittleEndianStringPerfTest { @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 f4380870f7fc..601ff3461f5b 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest { @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 78df5c0eaf07..0e567f9568e6 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest { @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 f45cc6247fc0..6be287006f42 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTes @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 08aa7e254dcb..84c186bd24e6 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 @@ import java.lang.invoke.VarHandle; @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 5d4b2e0978f3..b093234b2bc5 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest { @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 ba4f2c8a8d7d..0d2037b4ab27 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest { @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 7fca4504b2c6..ee31973c308a 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandsetFieldLittleEndianIntPerfTest { @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 7eb7ac026517..0571fefe2a43 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandsetFieldLittleEndianStringPerfTest { @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 ddfd407eda11..f619dabdd50a 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest { @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 f1f39681dce0..fc443fa362bc 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest { @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 09127c4eed7b..bf3d58b68692 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetAcquireFieldLittleEndianIntPerfTest { @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 87be4a66aa52..1f4bc31f24c6 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetAcquireFieldLittleEndianStringPerfTest { @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 5d5fc110cbaf..2085552e91dd 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest { @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 c7034b80a008..d9c7d7b7695e 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest { @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 f22865b01009..acd2533a38e4 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 @@ import java.lang.invoke.VarHandle; @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 class VarHandleGetArrayLittleEndianIntPerfTest { 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 fdb9e84fa847..de9944a8c274 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 @@ import java.lang.invoke.VarHandle; @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 class VarHandleGetArrayLittleEndianStringPerfTest { 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 347b0cf4effb..a8639292cbb3 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 org.junit.runner.RunWith; 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 class VarHandleGetByteArrayViewBigEndianIntPerfTest { 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 dedc94f278bf..4999b9bf6850 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 org.junit.runner.RunWith; 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 class VarHandleGetByteArrayViewLittleEndianIntPerfTest { 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 3f0f624dfccb..ee80a6f72c93 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetFieldLittleEndianIntPerfTest { @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 9db6328ea4c5..ec29f7a33b39 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetFieldLittleEndianStringPerfTest { @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 17b74a8d807e..ee6a669f2f83 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetOpaqueFieldLittleEndianIntPerfTest { @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 5df13800365b..1702b84e703b 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetOpaqueFieldLittleEndianStringPerfTest { @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 f656ef239625..514ddb9c4b11 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest { @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 1087df3d11c5..fbcee6906bd7 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest { @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 004345187c96..2c5658810b05 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetStaticFieldLittleEndianIntPerfTest { @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 0162637f7a64..8fce69e62033 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetStaticFieldLittleEndianStringPerfTest { @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 b0c4631574e8..ef530607bb56 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetVolatileFieldLittleEndianIntPerfTest { @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 5cbbc08521ad..64c08983a063 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetVolatileFieldLittleEndianStringPerfTest { @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 368ae69ab8f5..939100c47c05 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest { @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 3387a8da60c1..728b1995ff52 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest { @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 781e04f6b818..bf5ef99ff456 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest { @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 97f29ba38bc1..d15705e9106d 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest { @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 e108f7f4edbc..222a60da3550 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest { @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 d0ae322987f3..7436476b5329 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest { @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 1b80c4064741..cca97f42e4b7 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddFieldLittleEndianFloatPerfTest { @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 edacf181149b..170ee7313891 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddFieldLittleEndianIntPerfTest { @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 0e86b0d6f76b..184f796ad61c 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest { @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 83446ff85b9a..7e75c44089ff 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest { @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 c1f1e6f44c80..39c386b645d8 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest { @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 1b154a157622..04ab5310655c 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest { @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 7de128d7a5a5..b71351fca81c 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest { @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 c9a0926db637..e3955c051890 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandaddStaticFieldLittleEndianIntPerfTest { @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 fd9d9b13e9b2..adf05a6befb1 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest { @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 c3c367f80c26..4d657d9a3511 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest @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 e073d28a820f..dc6417416917 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest { @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 ca78f5ac53ec..25d5631308ef 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest { @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 599f18669695..de2d5489dbcc 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest @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 71fc0ae08196..36544c6f8f50 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest { @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 8fc4eabbaccc..fb36d0cb495f 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest { @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 33689533d565..4194b12a4a6e 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest { @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 583a3a029059..355c6e823803 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest { @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 1592fa6b9a8c..401079d0bece 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest { @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 d496083416a3..322dcbf7453e 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest { @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 87276a591699..c98281416012 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest { @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 f7a372fc806f..0b1cb32528ff 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest { @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 22726fcaa151..473707201782 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest @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 d071d6ead1ef..204cd70b2f9e 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest { @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 be2aa9cf61b4..b3ffed7de91a 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest { @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 b0a7dcf2e7d3..d0ab8de4502d 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest @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 c5f99deff29c..b378b684114e 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest { @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 572e0c8dc57b..c7c66fe20513 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest { @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 09be6d9d3204..98d6bd71c610 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest { @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 4e0554a541b2..206358f21c1d 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest { @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 5491522b0122..0532e73c9d66 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest { @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 a9303c6cff57..f192d7153fce 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetFieldLittleEndianIntPerfTest { @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 bd4703f6a5d6..0a8909c6c7b5 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetFieldLittleEndianStringPerfTest { @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 d9aee0037a0c..bfcb0f410256 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest { @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 2c79ca2634b3..c6b0509d619b 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest { @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 ceff81634f62..45a01eda2fd5 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest { @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 9b83504b94d6..30472811d5d6 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest { @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 638da6fd37b6..6f1f1a016039 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetStaticFieldLittleEndianIntPerfTest { @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 25d411417fb8..c4d279f37a4c 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleGetandsetStaticFieldLittleEndianStringPerfTest { @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 64ea9f32b698..c4f600593067 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 @@ import java.lang.invoke.VarHandle; @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 class VarHandleSetArrayLittleEndianIntPerfTest { 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 989d682f1b9f..a6858c261eb0 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 @@ import java.lang.invoke.VarHandle; @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 class VarHandleSetArrayLittleEndianStringPerfTest { 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 9d6d6b8c0963..a994cbeaf02c 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 e8c3fa3cd01b..65412ec84aa4 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 08294c06d438..573b0ff277cc 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetFieldLittleEndianIntPerfTest { @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 1e8a5bfd2a53..fe3c0fc04a84 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetFieldLittleEndianStringPerfTest { @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 2e5fb1815b4b..f398899880ce 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetOpaqueFieldLittleEndianIntPerfTest { @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 86a771f75b73..74931205fd3e 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetOpaqueFieldLittleEndianStringPerfTest { @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 903b31003510..5e7326985c9d 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest { @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 63cf7d25d0fd..9a217d1fd142 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest { @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 d1a358dc662e..1ce2270ecc58 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetReleaseFieldLittleEndianIntPerfTest { @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 b65832469685..ed84528fe869 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetReleaseFieldLittleEndianStringPerfTest { @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 47cb77959f2e..aeb96404a223 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest { @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 e48374e2224a..8959a0c3d50c 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest { @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 0470d67180c9..400772231d48 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetStaticFieldLittleEndianIntPerfTest { @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 00abb0bab6bb..732315862eb2 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetStaticFieldLittleEndianStringPerfTest { @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 c66b23b19938..f4119c28b826 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetVolatileFieldLittleEndianIntPerfTest { @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 1b364504d1d5..9b9c2612fe25 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetVolatileFieldLittleEndianStringPerfTest { @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 75f927494f88..f125384706ca 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest { @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 8289d4fdc0aa..2ad605d83d04 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest { @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 9fac8427eacf..5ef3bf00204b 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest { @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 2f601273076e..0c4ed66fc6b7 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest { @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 4efbd3e50637..db6bd2429e26 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest @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 099640c624e1..d2b0bf76158f 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 @@ import java.lang.invoke.VarHandle; @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 ce8f0f0ac269..3cd5ae6533b6 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest { @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 c4119dc5411b..6ddfc25deca9 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest { @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 abd981c78f41..375f0bc08027 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest { @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 c71e65f77983..7e2492ace1dd 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest { @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 f3c8f3ac0656..190118c551e6 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest { @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 5c943a46cedc..484ba1b88183 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTes @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 1755a15aae76..80e4e153a41f 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest { @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 77175b007af9..fa26c59304f9 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest { @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 985519e890af..16bf2a208870 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest @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 69e6ca7cce9c..e1716dede024 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 @@ import java.lang.invoke.VarHandle; @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 88df5ff60341..dc6f2adfe951 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest { @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 c296f66814a4..d1096c629ed8 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 @@ import java.lang.invoke.VarHandle; @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 @@ public class VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest { @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 a43569a13813..4b4bc605a6c3 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 @@ def to_camel_case(word): 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 @@ BANNER = """/* 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 @@ VH_START = BANNER + VH_IMPORTS + """ @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 @@ VH_START_ARRAY = BANNER + VH_IMPORTS + """ @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 @@ import java.nio.ByteOrder; @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 @@ import java.lang.reflect.Field; @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 @@ import jdk.internal.misc.Unsafe; @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 16c2fd4b73c3..a0bf78f28127 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 dd0d1b6285de..f56c14da8f23 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 c009c1f5b08b..16026eca2980 100644 --- a/cmds/screencap/Android.bp +++ b/cmds/screencap/Android.bp @@ -17,6 +17,7 @@ cc_binary { "libutils", "libbinder", "libjnigraphics", + "libhwui", "libui", "libgui", ], diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 01b20f4a5267..12de82a46263 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 @@ enum { }; } -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 @@ status_t capture(const DisplayId displayId, 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 @@ status_t saveImage(const char* fn, bool png, const ScreenCaptureResults& capture 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 @@ status_t saveImage(const char* fn, bool png, const ScreenCaptureResults& capture 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 @@ status_t saveImage(const char* fn, bool png, const ScreenCaptureResults& capture } close(fd); + if (gainmapBase) { + gainmap->unlock(); + } + + if (base) { + buffer->unlock(); + } + return 0; } @@ -262,13 +305,17 @@ int main(int argc, char** argv) 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 @@ int main(int argc, char** argv) 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 @@ int main(int argc, char** argv) } } + 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 @@ int main(int argc, char** argv) 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 5cdc57a0dc2a..520c7d1d02f2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6396,6 +6396,7 @@ package android.app { 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 @@ package android.app { 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 @@ package android.hardware.camera2 { 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 @@ package android.hardware.camera2 { 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 @@ package android.hardware.camera2.params { 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 @@ package android.view { 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 df707d18a827..1e94c2fc219c 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -673,8 +673,8 @@ package android.webkit { 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 fb425a99732a..9c807afb06a8 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4972,12 +4972,12 @@ package android.hardware.camera2.extension { @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 @@ package android.hardware.camera2.extension { @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 @@ package android.webkit { 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 4fc70769a3b1..caf699280e08 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2321,7 +2321,7 @@ package android.os { } 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 53eddbee6b03..432a0da15a47 100644 --- a/core/java/android/app/CameraCompatTaskInfo.java +++ b/core/java/android/app/CameraCompatTaskInfo.java @@ -36,20 +36,36 @@ public class CameraCompatTaskInfo implements Parcelable { 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 @@ public class CameraCompatTaskInfo implements Parcelable { @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 45852c7d338a..93a9489849af 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -2408,9 +2408,9 @@ public class Instrumentation { * @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 7a36fbb55dc4..81d2c890ee31 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1281,6 +1281,15 @@ public class Notification implements Parcelable 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 @@ public class Notification implements Parcelable 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 @@ public class Notification implements Parcelable } /** + * 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 32e9542e91a7..4a2b016456f7 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -55,7 +55,9 @@ import java.io.IOException; 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 @@ public final class NotificationChannel implements Parcelable { @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 e44e7768724e..5147f12018cf 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -104,6 +104,7 @@ import android.debug.IAdbManager; 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 @@ public final class SystemServiceRegistry { 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 c7b0be7553c2..46567c440111 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -1107,7 +1107,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { /** * 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 085e0a47d356..a23f842e6eeb 100644 --- a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java +++ b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java @@ -37,6 +37,8 @@ import java.util.Objects; 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 000000000000..5657f7ee5194 --- /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 60d1b0d45365..e895d7be1102 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -3141,14 +3141,6 @@ public class IntentFilter implements Parcelable { 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 26bb6e4df325..fb2655c771c4 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8842,6 +8842,7 @@ public abstract class PackageManager { 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 7c2edd7bbc17..139ff65b4d86 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -285,4 +285,12 @@ flag { 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 4cdaaddd05bf..a4c0e87c965b 100644 --- a/core/java/android/hardware/SensorPrivacyManager.java +++ b/core/java/android/hardware/SensorPrivacyManager.java @@ -797,7 +797,7 @@ public final class SensorPrivacyManager { 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 @@ public final class SensorPrivacyManager { @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 @@ public final class SensorPrivacyManager { @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 @@ public final class SensorPrivacyManager { @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 056ca93159dd..7a8a16f4b98a 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -567,7 +567,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * @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 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri */ @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 6a7ee7fcb26a..d40b2e342fbb 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -29,6 +29,7 @@ import android.annotation.SystemApi; 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 @@ public final class CameraManager { 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 @@ public final class CameraManager { : 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 001b79499b1a..32139b8e314b 100644 --- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java +++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java @@ -107,7 +107,6 @@ public final class CameraOutputSurface { * {@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 @@ public final class CameraOutputSurface { * unless specified by CameraOutputSurface.setColorSpace. */ @SuppressLint("MethodNameUnits") - @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT) public int getColorSpace() { return mOutputSurface.colorSpace; } @@ -128,7 +126,6 @@ public final class CameraOutputSurface { * 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 84b7a7fc1349..32de1ce8f0d6 100644 --- a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java +++ b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java @@ -83,7 +83,6 @@ public class ExtensionConfiguration { * 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 @@ public class ExtensionConfiguration { 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 3a67d6192f5e..8a47430e7eb4 100644 --- a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java +++ b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java @@ -80,11 +80,7 @@ public class ExtensionOutputConfiguration { 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 2e1e90c78f3a..323712d817af 100644 --- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java @@ -148,7 +148,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes 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 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes 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,23 +357,21 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes 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; - } - } - if (validDynamicRangeProfile) { - cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile); - } else { - Log.e(TAG, "Extension configured dynamic range profile " - + output.dynamicRangeProfile - + " is not valid, using default DynamicRangeProfile.STANDARD"); + 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"); + } outputList.add(cameraOutput); mCameraConfigMap.put(cameraOutput.getSurface(), output); } @@ -390,15 +386,13 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes 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 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes 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 a10e2505758e..ab4ff72bb952 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java @@ -208,10 +208,6 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { } 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 class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { 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 class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { } 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 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { 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 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { 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 a4ae398782b4..ce1609dec4e6 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java @@ -190,9 +190,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { 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 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { 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 40f047732c06..f91d277d571f 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java @@ -113,32 +113,13 @@ public final class CameraExtensionUtils { 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 @@ public final class CameraExtensionUtils { 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 bf3f59fc7480..73f4ff480259 100644 --- a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java @@ -136,7 +136,6 @@ public final class ExtensionSessionConfiguration { * 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 @@ public final class ExtensionSessionConfiguration { /** * 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 @@ public final class ExtensionSessionConfiguration { * @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 85e33a8b4496..9612a53be96e 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -21,6 +21,7 @@ import static android.hardware.display.DisplayManager.EventsMask; 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 @@ public final class DisplayManagerGlobal { } /** + * @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 f3c21e9f7a43..aa1539f69722 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -247,6 +247,9 @@ interface IDisplayManager { @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/core/java/android/hardware/input/AidlKeyGestureEvent.aidl b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl new file mode 100644 index 000000000000..7cf8795085e3 --- /dev/null +++ b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl @@ -0,0 +1,29 @@ +/* + * 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; + +/** @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 2d96bbaae901..102f56e4672b 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.IInputDeviceBatteryState; 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 @@ interface IInputManager { @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 2c430f1a1c9d..6b5f83758a11 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 000000000000..509b9482154e --- /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 04cfcd880f52..22728f7a5ad3 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1406,6 +1406,33 @@ public final class InputManager { } /** + * 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 @@ public final class InputManager { */ 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 2a362381a003..5c11346df1c3 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -25,6 +25,7 @@ import android.hardware.BatteryState; 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 @@ public final class InputManagerGlobal { @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 @@ public final class InputManagerGlobal { } 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 @@ public final class InputManagerGlobal { } } + 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 7a8dd3395d21..c7ebc63a3d15 100644 --- a/core/java/android/hardware/input/KeyGestureEvent.java +++ b/core/java/android/hardware/input/KeyGestureEvent.java @@ -19,8 +19,11 @@ package android.hardware.input; 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 @@ import java.lang.annotation.RetentionPolicy; * * @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; - - - 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; - - - - // 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 - + 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 FLAG_CANCELLED = 1; + + // NOTE: Valid KeyGestureEvent streams: + // - GESTURE_START -> GESTURE_CANCEL + // - GESTURE_START -> GESTURE_COMPLETE + // - GESTURE_COMPLETE + + /** 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 { + } + + 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); + } + } + + public int getDeviceId() { + return mKeyGestureEvent.deviceId; + } + + public @NonNull int[] getKeycodes() { + return mKeyGestureEvent.keycodes; + } + + public int getModifierState() { + return mKeyGestureEvent.modifierState; + } + + public @KeyGestureType int getKeyGestureType() { + return mKeyGestureEvent.gestureType; + } + + public int getAction() { + return mKeyGestureEvent.action; + } + + public int getDisplayId() { + return mKeyGestureEvent.displayId; + } - @DataClass.Generated.Member - public static String keyGestureTypeToString(@KeyGestureType int value) { + public int getFlags() { + return mKeyGestureEvent.flags; + } + + public boolean isCancelled() { + return (mKeyGestureEvent.flags & FLAG_CANCELLED) != 0; + } + + @Override + public String toString() { + 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 + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KeyGestureEvent that = (KeyGestureEvent) o; + 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 + public int hashCode() { + int _hash = 1; + _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; + } + + /** + * Convert KeyGestureEvent type to corresponding log event got KeyboardSystemsEvent + */ + public static int keyGestureTypeToLogEvent(@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"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME; case KEY_GESTURE_TYPE_RECENT_APPS: - return "KEY_GESTURE_TYPE_RECENT_APPS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS; case KEY_GESTURE_TYPE_BACK: - return "KEY_GESTURE_TYPE_BACK"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK; case KEY_GESTURE_TYPE_APP_SWITCH: - return "KEY_GESTURE_TYPE_APP_SWITCH"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH; case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT: - return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT; case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT: - return "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 "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 "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 "KEY_GESTURE_TYPE_TOGGLE_TASKBAR"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR; case KEY_GESTURE_TYPE_TAKE_SCREENSHOT: - return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT; case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER: - return "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 "KEY_GESTURE_TYPE_BRIGHTNESS_UP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP; case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN: - return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN; case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP: - return "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 "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 "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 "KEY_GESTURE_TYPE_VOLUME_UP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP; case KEY_GESTURE_TYPE_VOLUME_DOWN: - return "KEY_GESTURE_TYPE_VOLUME_DOWN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN; case KEY_GESTURE_TYPE_VOLUME_MUTE: - return "KEY_GESTURE_TYPE_VOLUME_MUTE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE; case KEY_GESTURE_TYPE_ALL_APPS: - return "KEY_GESTURE_TYPE_ALL_APPS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS; case KEY_GESTURE_TYPE_LAUNCH_SEARCH: - return "KEY_GESTURE_TYPE_LAUNCH_SEARCH"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH; case KEY_GESTURE_TYPE_LANGUAGE_SWITCH: - return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH; case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS: - return "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 "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 "KEY_GESTURE_TYPE_SYSTEM_MUTE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE; case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION: - return "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 "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 "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 "KEY_GESTURE_TYPE_LOCK_SCREEN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN; case KEY_GESTURE_TYPE_OPEN_NOTES: - return "KEY_GESTURE_TYPE_OPEN_NOTES"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES; case KEY_GESTURE_TYPE_TOGGLE_POWER: - return "KEY_GESTURE_TYPE_TOGGLE_POWER"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER; case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION: - return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION; case KEY_GESTURE_TYPE_SLEEP: - return "KEY_GESTURE_TYPE_SLEEP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP; case KEY_GESTURE_TYPE_WAKEUP: - return "KEY_GESTURE_TYPE_WAKEUP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP; case KEY_GESTURE_TYPE_MEDIA_KEY: - return "KEY_GESTURE_TYPE_MEDIA_KEY"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER: - return "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "KEY_GESTURE_TYPE_DESKTOP_MODE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE; case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION: - return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION"; - default: return Integer.toHexString(value); + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION; + default: + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED; } } - @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 + ")"); + 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); } - - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public int getDeviceId() { - return mDeviceId; } - - @DataClass.Generated.Member - public @NonNull int[] getKeycodes() { - return mKeycodes; - } - - @DataClass.Generated.Member - public int getModifierState() { - return mModifierState; - } - - @DataClass.Generated.Member - public @KeyGestureType int getKeyGestureType() { - return mKeyGestureType; - } - - @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) + - " }"; - } - - @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; - } - - @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; - 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() {} - - - //@formatter:on - // End of generated code - } diff --git a/core/java/android/hardware/input/VirtualInputDeviceConfig.java b/core/java/android/hardware/input/VirtualInputDeviceConfig.java index a87980c34f2d..e8ef8cd11585 100644 --- a/core/java/android/hardware/input/VirtualInputDeviceConfig.java +++ b/core/java/android/hardware/input/VirtualInputDeviceConfig.java @@ -57,7 +57,7 @@ public abstract class VirtualInputDeviceConfig { 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 @@ public abstract class VirtualInputDeviceConfig { 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 c4d12d4336c6..996a288ef59d 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2066,9 +2066,11 @@ public abstract class BatteryStats { 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 abstract class BatteryStats { 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 f7b417337911..93a8ed96b675 100644 --- a/core/java/android/os/BugreportParams.java +++ b/core/java/android/os/BugreportParams.java @@ -134,7 +134,6 @@ public final class BugreportParams { * 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 360b2ac4f3ca..73cdd5682f31 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -33,7 +33,7 @@ interface IHintManager { * 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 @@ interface IHintManager { * * 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 bf44d65c4002..0776cf405cfe 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 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query, } /** - * 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 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query, } /** + * 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 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query, } } + /** * 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 3b2041b0d50a..346ee7ca4f87 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -589,6 +589,12 @@ public class Process { **/ 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 58ab5b6fd7ca..cfbf5289931d 100644 --- a/core/java/android/os/SystemVibratorManager.java +++ b/core/java/android/os/SystemVibratorManager.java @@ -138,11 +138,14 @@ public class SystemVibratorManager extends VibratorManager { 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 @@ public class SystemVibratorManager extends VibratorManager { 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 @@ public class SystemVibratorManager extends VibratorManager { + " 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 f1ec0e4e9bdc..a4a7a983c44c 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1539,10 +1539,19 @@ public class UserManager { * 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 f026997bcc57..39bd15c968d7 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -52,14 +52,6 @@ flag { } 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 { } 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 bc6c5706f6fd..e6e5a27bd731 100644 --- a/core/java/android/os/vibrator/VibrationConfig.java +++ b/core/java/android/os/vibrator/VibrationConfig.java @@ -30,17 +30,13 @@ import static android.os.VibrationAttributes.USAGE_UNKNOWN; 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 @@ import java.util.function.Function; 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 @@ public class VibrationConfig { 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 @@ public class VibrationConfig { /** @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 @@ public class VibrationConfig { 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 @@ public class VibrationConfig { * 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 @@ public class VibrationConfig { return "VibrationConfig{" + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger + ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude - + ", mDefaultVibrationScaleLevelGain=" + mDefaultVibrationScaleLevelGain + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude + ", mRampStepDurationMs=" + mRampStepDurationMs + ", mRampDownDurationMs=" + mRampDownDurationMs @@ -353,7 +296,6 @@ public class VibrationConfig { 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 6c486dbfd7a2..b0791e36e124 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -249,3 +249,19 @@ flag { 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 0a05f704f523..e32625e1f7a8 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -17818,6 +17818,12 @@ public final class Settings { 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 f6f0eff918e3..a86c961e6785 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -99,3 +99,10 @@ flag { 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 3d8d933cbbcc..752f174504f2 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -2553,7 +2553,7 @@ public class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { } } - // 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 @@ public class ZenModeConfig implements Parcelable { // 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 05c2a9c26709..60a7d6b5a3be 100644 --- a/core/java/android/service/notification/ZenModeDiff.java +++ b/core/java/android/service/notification/ZenModeDiff.java @@ -495,8 +495,8 @@ public class ZenModeDiff { // 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 82c52a6e8931..f8c97eb5fa72 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -20,6 +20,8 @@ import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE; 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 @@ public final class Display { } /** + * @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 e9c85684dbd8..658aa29a3cc6 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 @@ flag { 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 0eb710015ea9..b9a5e4aedeb9 100644 --- a/core/java/android/webkit/WebViewUpdateManager.java +++ b/core/java/android/webkit/WebViewUpdateManager.java @@ -43,22 +43,29 @@ public final class WebViewUpdateManager { /** * 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 @@ public final class WebViewUpdateManager { /** * 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 @@ public final class WebViewUpdateManager { /** * 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 @@ public final class WebViewUpdateManager { /** * 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 @@ public final class WebViewUpdateManager { /** * 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 01af182a10fa..644d917c8be6 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 @@ public final class WebViewUpdateService { /** * 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 89ea85200cd6..e1154ca0701c 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -83,6 +83,7 @@ import android.os.Parcelable; 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 @@ public class RemoteViews implements Parcelable, Filter { 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 @@ public class RemoteViews implements Parcelable, Filter { 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 @@ public class RemoteViews implements Parcelable, Filter { 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 @@ public class RemoteViews implements Parcelable, Filter { } 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 bccee9215c2d..0632a37a5dfb 100644 --- a/core/java/android/window/OnBackInvokedDispatcher.java +++ b/core/java/android/window/OnBackInvokedDispatcher.java @@ -76,7 +76,7 @@ public interface OnBackInvokedDispatcher { * @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 index d33313e08742..5c53d66e49fe 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 com.android.window.flags.Flags; 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 @@ public enum DesktopModeFlagsUtil { // 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 @@ public enum DesktopModeFlagsUtil { 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 8e81951ba4ca..0f401d3e60b1 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 { } 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 { } 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 a786fc24d9a7..69b91fdfaa98 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -144,6 +144,13 @@ flag { } 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 { } 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 8077a55bf74d..13648de5b28e 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -115,3 +115,10 @@ flag { 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 ebcae277c62b..a5e166b95177 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -144,9 +144,9 @@ interface IBatteryStats { @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 b873175451e1..39aadfb24b0c 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 @@ package com.android.internal.pm.pkg.component; 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 org.xmlpull.v1.XmlPullParserException; 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 @@ import java.util.Map; 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 @@ public class AconfigFlags { 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 e5ac0e1a8f6e..49191ee02ad6 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -404,6 +404,11 @@ static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set) 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 c1022a54207d..664d54d374b4 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -43,3 +43,10 @@ filegroup { 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 5111d2d1e044..d98836f8ce20 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -303,6 +303,7 @@ test_module_config { name: "FrameworksCoreTests_Presubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -313,6 +314,7 @@ test_module_config { name: "FrameworksCoreTests_inputmethod", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -327,6 +329,7 @@ test_module_config { name: "FrameworksCoreTests_context", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -337,6 +340,7 @@ test_module_config { name: "FrameworksCoreTests_keyguard_manager", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -347,6 +351,7 @@ test_module_config { name: "FrameworksCoreTests_property_invalidated_cache", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -357,6 +362,7 @@ test_module_config { name: "FrameworksCoreTests_android_content", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -371,6 +377,7 @@ test_module_config { name: "FrameworksCoreTests_sqlite", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -381,6 +388,7 @@ test_module_config { name: "FrameworksCoreTests_android_net", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -392,6 +400,7 @@ test_module_config { name: "FrameworksCoreTests_battery_stats", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -403,6 +412,7 @@ test_module_config { name: "FrameworksCoreTests_environment", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -413,6 +423,7 @@ test_module_config { name: "FrameworksCoreTests_util_data_charset", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -426,6 +437,7 @@ test_module_config { name: "FrameworksCoreTests_xml", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -439,6 +451,7 @@ test_module_config { name: "FrameworksCoreTests_util_apk", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -449,6 +462,7 @@ test_module_config { name: "FrameworksCoreTests_textclassifier", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -460,6 +474,7 @@ test_module_config { name: "FrameworksCoreTests_internal_app", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -474,6 +489,7 @@ test_module_config { name: "FrameworksCoreTests_internal_content", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -484,6 +500,7 @@ test_module_config { name: "FrameworksCoreTests_internal_infra", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -494,6 +511,7 @@ test_module_config { name: "FrameworksCoreTests_internal_jank", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -504,6 +522,7 @@ test_module_config { name: "FrameworksCoreTests_internal_os_binder", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -515,6 +534,7 @@ test_module_config { name: "FrameworksCoreTests_internal_os_kernel", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -531,6 +551,7 @@ test_module_config { name: "FrameworksCoreTests_server_power", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -541,6 +562,7 @@ test_module_config { name: "FrameworksCoreTests_internal_security", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -552,6 +574,7 @@ test_module_config { name: "FrameworksCoreTests_internal_util_latency_tracker", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -562,6 +585,7 @@ test_module_config { name: "FrameworksCoreTests_content_capture_options", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -572,6 +596,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_integrity", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -582,6 +607,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_pm_PreSubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -593,6 +619,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_pm_PostSubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -604,6 +631,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_res", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -620,6 +648,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_res_PostSubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -631,6 +660,7 @@ test_module_config { name: "FrameworksCoreTests_android_service", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -650,6 +680,7 @@ test_module_config { name: "FrameworksCoreTests_android_view_contentcapture", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -660,6 +691,7 @@ test_module_config { name: "FrameworksCoreTests_android_view_contentprotection", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -670,6 +702,7 @@ test_module_config { name: "FrameworksCoreTests_com_android_internal_content_Presubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -681,6 +714,7 @@ test_module_config { name: "FrameworksCoreTests_drawable", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -691,6 +725,7 @@ test_module_config { name: "FrameworksCoreTests_accessibility", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -705,6 +740,7 @@ test_module_config { name: "FrameworksCoreTests_usage", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -715,6 +751,7 @@ test_module_config { name: "FrameworksCoreTests_fastdata", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -725,6 +762,7 @@ test_module_config { name: "FrameworksCoreTests_hardware_input", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -735,6 +773,7 @@ test_module_config { name: "FrameworksCoreTests_view_verified", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -745,9 +784,34 @@ test_module_config { } 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 @@ test_module_config { 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 ef6ff0518dac..0837b458c3ba 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -215,6 +215,25 @@ public class NotificationTest { } @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 b03fd6485786..64f77b309829 100644 --- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java +++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java @@ -18,7 +18,9 @@ package android.os; 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 @@ public class IpcDataCacheTest { 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 @@ public class IpcDataCacheTest { } @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 index 46b8e3a430c8..32345e606229 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 android.window.flags.DesktopModeFlags.DESKTOP_WINDOWING_MODE; -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 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.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPT 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 org.junit.runner.RunWith; 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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { 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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { 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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { }) @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { 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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { }) @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { 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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { }) @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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { 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 @@ public class DesktopModeFlagsUtilTest extends WindowTestsBase { } 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 e0f101229080..74c7b4ca4206 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 @@ android_test_helper_app { "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 a2ff9d77674a..000000000000 --- 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 bc46b70793cd..bd430c0e610b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp +++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp @@ -62,3 +62,10 @@ android_test { 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 a79bc97c440c..94809f2d258f 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -187,6 +187,9 @@ java_library { "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 c6044a45200d..394093c6ab30 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 1871203c7600..b6db6d93499d 100644 --- a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp @@ -72,8 +72,8 @@ android_test { "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 000000000000..7d912a24c443 --- /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 eea3de8e30ca..64f71c713d1c 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 755e0d5f742d..c76c47041ebf 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 a353db72b914..a6da421dbbb9 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 000000000000..79becb0a2e20 --- /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 133242d15822..a27caf879e8a 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 @@ public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithmInterfac 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 140d7765e5c1..c487f7543dcf 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 @@ public class PipBoundsState { @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 class PipBoundsState { 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 @@ public class PipBoundsState { 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 @@ public class PipBoundsState { /** 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 @@ public class PipBoundsState { /** 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 7054c17cfeb0..8c7dcf295319 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 @@ package com.android.wm.shell.dagger; 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.unfold.qualifier.UnfoldTransition; 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 @@ public abstract class WMShellModule { 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 @@ public abstract class WMShellModule { assistContentRequester, multiInstanceHelper, desktopTasksLimiter, - desktopActivityOrientationHandler); + desktopActivityOrientationHandler, + windowDecorViewHostSupplier); } return new CaptionWindowDecorViewModel( context, @@ -282,7 +287,8 @@ public abstract class WMShellModule { displayController, rootTaskDisplayAreaOrganizer, syncQueue, - transitions); + transitions, + windowDecorViewHostSupplier); } @WMSingleton @@ -371,6 +377,13 @@ public abstract class WMShellModule { 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 1d16980c617d..7e9625361efc 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 @@ class DesktopTasksController( 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 @@ class DesktopTasksController( } } + 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 d72ec90957fc..dfc5ab377817 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 @@ sealed class DragToDesktopTransitionHandler( 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 cf02fb5fde8e..22e8dc186e9b 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.DragEvent.ACTION_DROP; 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 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll 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 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll @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 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll 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 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll // 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 3fecbe7fff74..dfa24370590a 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.content.pm.ActivityInfo.CONFIG_UI_MODE; 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.Region; 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.shared.animation.Interpolators; 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 @@ public class DragLayout extends LinearLayout | 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 @@ public class DragLayout extends LinearLayout // 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 @@ public class DragLayout extends LinearLayout 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 @@ public class DragLayout extends LinearLayout 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 @@ public class DragLayout extends LinearLayout 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 @@ public class DragLayout extends LinearLayout } // 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 @@ public class DragLayout extends LinearLayout 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 @@ public class DragLayout extends LinearLayout } } - 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 000000000000..3d408242f5f8 --- /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 000000000000..122a105dbf8d --- /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 index 6fec0c1c20bc..2a19d6512b56 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.EXTRA_USER; 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 @@ import java.util.ArrayList; /** * 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 @@ public class DragAndDropPolicy { // 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 @@ public class DragAndDropPolicy { /** * 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 @@ public class DragAndDropPolicy { /** * Returns the number of targets. */ - int getNumTargets() { + @Override + public int getNumTargets() { return mTargets.size(); } @@ -136,7 +137,8 @@ public class DragAndDropPolicy { * 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 @@ public class DragAndDropPolicy { * 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 @@ public class DragAndDropPolicy { * 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 @@ public class DragAndDropPolicy { /** * 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 ab222c9cdbf6..b4e03299f14c 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 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, 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 755e9581326a..deb7691f2d4d 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 @@ public class PipController implements PipTransitionController.PipTransitionCallb return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId), - false /* saveRestoreSnapFraction */); + true /* saveRestoreSnapFraction */); } @Override @@ -652,9 +652,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb // 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 @@ public class PipController implements PipTransitionController.PipTransitionCallb } }; - 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 793e2aa757a3..87b661d340ed 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.SyncTransactionQueue; 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 @@ import java.util.concurrent.atomic.AtomicBoolean; * @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 1b143ebddde7..4ba84eeb2e6d 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.view.WindowManager.transitTypeToString; 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 11976aed9315..015139519f1f 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.splitscreen.SplitScreenController; 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 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { DisplayController displayController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, SyncTransactionQueue syncQueue, - Transitions transitions) { + Transitions transitions, + WindowDecorViewHostSupplier windowDecorViewHostSupplier) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; @@ -132,6 +135,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mSyncQueue = syncQueue; mTransitions = transitions; + mWindowDecorViewHostSupplier = windowDecorViewHostSupplier; if (!Transitions.ENABLE_SHELL_TRANSITIONS) { mTaskOperations = new TaskOperations(null, mContext, mSyncQueue); } @@ -295,7 +299,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { 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 349ee0b1fcda..46fe68f44bed 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.ShellExecutor; 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 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL 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 000000000000..13a805aef0f1 --- /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 000000000000..05391a8343a5 --- /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 0f8bd2866fa8..2519ce4e6571 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.Indica 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; 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.DesktopModeWindowDecoration.ExclusionReg 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { AssistContentRequester assistContentRequester, MultiInstanceHelper multiInstanceHelper, Optional<DesktopTasksLimiter> desktopTasksLimiter, - Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler - ) { + Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, + WindowDecorViewHostSupplier windowDecorViewHostSupplier) { this( context, shellExecutor, @@ -244,6 +254,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { genericLinksParser, assistContentRequester, multiInstanceHelper, + windowDecorViewHostSupplier, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, @@ -275,6 +286,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { AppToWebGenericLinksParser genericLinksParser, AssistContentRequester assistContentRequester, MultiInstanceHelper multiInstanceHelper, + WindowDecorViewHostSupplier windowDecorViewHostSupplier, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, @@ -300,6 +312,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mMultiInstanceHelper = multiInstanceHelper; mShellCommandHandler = shellCommandHandler; mWindowManager = windowManager; + mWindowDecorViewHostSupplier = windowDecorViewHostSupplier; mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory; mInputMonitorFactory = inputMonitorFactory; mTransactionFactory = transactionFactory; @@ -580,6 +593,61 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { // 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mRootTaskDisplayAreaOrganizer, mGenericLinksParser, mAssistContentRequester, - mMultiInstanceHelper); + mMultiInstanceHelper, + mWindowDecorViewHostSupplier); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final TaskPositioner taskPositioner = mTaskPositionerFactory.create( @@ -1329,6 +1413,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } + /** + * 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 142be91fe942..5d16d972a0f2 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 static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResiz 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.View; 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.annotations.ShellBackgroundThread; 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } updateDragResizeListener(oldDecorationSurface); updateMaximizeMenu(startT); - Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces + Trace.endSection(); // DesktopModeWindowDecoration#relayout } private boolean isCaptionVisible() { @@ -638,6 +587,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin /** * 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mAppName, mSplitScreenController, DesktopModeStatus.canEnterDesktopMode(mContext), - Flags.enableDesktopWindowingMultiInstanceFeatures() - && mMultiInstanceHelper - .supportsMultiInstanceSplit(mTaskInfo.baseActivity), + supportsMultiInstance, + shouldShowManageWindowsButton, getBrowserLink(), mResult.mCaptionWidth, mResult.mCaptionHeight, @@ -1047,6 +1002,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin /* onToFullscreenClickListener= */ mOnToFullscreenClickListener, /* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener, /* onNewWindowClickListener= */ mOnNewWindowClickListener, + /* onManageWindowsClickListener= */ mOnManageWindowsClickListener, /* openInBrowserClickListener= */ (uri) -> { mOpenInBrowserClickListener.accept(uri); onCapturedLinkExpired(); @@ -1061,6 +1017,47 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId); disposeResizeVeil(); disposeStatusBarInputLayer(); - clearCurrentViewHostRunnable(); super.close(); } @@ -1364,7 +1360,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, AppToWebGenericLinksParser genericLinksParser, AssistContentRequester assistContentRequester, - MultiInstanceHelper multiInstanceHelper) { + MultiInstanceHelper multiInstanceHelper, + WindowDecorViewHostSupplier windowDecorViewHostSupplier) { return new DesktopModeWindowDecoration( context, userContext, @@ -1380,7 +1377,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 000000000000..e8131a00ba40 --- /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 748046ebd08d..3d00a445d9e0 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 @@ class HandleMenu( 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 @@ class HandleMenu( onToFullscreenClickListener: () -> Unit, onToSplitScreenClickListener: () -> Unit, onNewWindowClickListener: () -> Unit, + onManageWindowsClickListener: () -> Unit, openInBrowserClickListener: (Uri) -> Unit, onCloseMenuClickListener: () -> Unit, onOutsideTouchListener: () -> Unit, @@ -133,6 +135,7 @@ class HandleMenu( onToFullscreenClickListener = onToFullscreenClickListener, onToSplitScreenClickListener = onToSplitScreenClickListener, onNewWindowClickListener = onNewWindowClickListener, + onManageWindowsClickListener = onManageWindowsClickListener, openInBrowserClickListener = openInBrowserClickListener, onCloseMenuClickListener = onCloseMenuClickListener, onOutsideTouchListener = onOutsideTouchListener, @@ -150,6 +153,7 @@ class HandleMenu( onToFullscreenClickListener: () -> Unit, onToSplitScreenClickListener: () -> Unit, onNewWindowClickListener: () -> Unit, + onManageWindowsClickListener: () -> Unit, openInBrowserClickListener: (Uri) -> Unit, onCloseMenuClickListener: () -> Unit, onOutsideTouchListener: () -> Unit @@ -160,13 +164,15 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ class HandleMenu( 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 @@ interface HandleMenuFactory { splitScreenController: SplitScreenController, shouldShowWindowingPill: Boolean, shouldShowNewWindowButton: Boolean, + shouldShowManageWindowsButton: Boolean, openInBrowserLink: Uri?, captionWidth: Int, captionHeight: Int, @@ -661,6 +687,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { splitScreenController: SplitScreenController, shouldShowWindowingPill: Boolean, shouldShowNewWindowButton: Boolean, + shouldShowManageWindowsButton: Boolean, openInBrowserLink: Uri?, captionWidth: Int, captionHeight: Int, @@ -675,6 +702,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { 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 4af5b2c95cd5..369484558325 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.shared.desktopmode.DesktopModeStatus; 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> ? 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } } - /** - * 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> boolean mApplyStartTransactionOnDraw; boolean mSetTaskPositionAndCrop; + boolean mAsyncViewHost; void reset() { mLayoutResId = Resources.ID_NULL; @@ -751,6 +725,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 000000000000..139e6790b744 --- /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 000000000000..9997e8f564d8 --- /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 000000000000..3fbaea8bd1bf --- /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 000000000000..0e2358446d12 --- /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 5b028371be2b..497d0e51e553 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.TransitionInfo.FLAG_IS_WALLPAPER 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 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { ) } + @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 index 645b296930f8..46b60499a01d 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.dx.mockito.inline.extended.ExtendedMockito.mockitoSess 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 androidx.test.filters.SmallTest; 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 @@ import java.util.HashSet; */ @SmallTest @RunWith(AndroidJUnit4.class) -public class DragAndDropPolicyTest extends ShellTestCase { +public class SplitDragPolicyTest extends ShellTestCase { @Mock private Context mContext; @@ -104,7 +104,7 @@ public class DragAndDropPolicyTest extends ShellTestCase { @Mock private SplitScreenController mSplitScreenStarter; @Mock - private DragAndDropPolicy.Starter mFullscreenStarter; + private SplitDragPolicy.Starter mFullscreenStarter; @Mock private InstanceId mLoggerSessionId; @@ -112,7 +112,7 @@ public class DragAndDropPolicyTest extends ShellTestCase { 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 @@ public class DragAndDropPolicyTest extends ShellTestCase { 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 @@ public class DragAndDropPolicyTest extends ShellTestCase { 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 @@ public class DragAndDropPolicyTest extends ShellTestCase { 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 @@ public class DragAndDropPolicyTest extends ShellTestCase { 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 8c7b47ea7d84..e3798e92c092 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { 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 6ddb6781c80c..f3944d5ac352 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 @@ public class PipControllerTest extends ShellTestCase { 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 2c805e8e77b3..a17d08d8fbfb 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.sysui.ShellInit 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 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @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 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockGenericLinksParser, mockAssistContentRequester, mockMultiInstanceHelper, + mockWindowDecorViewHostSupplier, mockDesktopModeWindowDecorFactory, mockInputMonitorFactory, transactionFactory, @@ -1197,7 +1200,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { 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 b9e542a0e0c1..1741fe447fad 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.common.SyncTransactionQueue; 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 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @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 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { 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 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { 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,58 +515,55 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } @Test - public void relayout_fullscreenTask_appliesTransactionImmediately() { + public void updateRelayoutParams_handle_requestsAsyncViewHostRendering() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); + // Make the task fullscreen so that its decoration is an App Handle. taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + final RelayoutParams relayoutParams = new RelayoutParams(); - spyWindowDecor.relayout(taskInfo); + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, + mTestableContext, + taskInfo, + /* applyStartTransactionOnDraw= */ true, + /* shouldSetTaskPositionAndCrop */ false); - verify(mMockTransaction).apply(); - verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any()); + // App Handles don't need to be rendered in sync with the task animation, per UX. + assertThat(relayoutParams.mAsyncViewHost).isTrue(); } @Test - public void relayout_freeformTask_appliesTransactionOnDraw() { + public void updateRelayoutParams_header_requestsSyncViewHostRendering() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); + // Make the task freeform so that its decoration is an App Header. 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(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); + final RelayoutParams relayoutParams = new RelayoutParams(); - spyWindowDecor.relayout(taskInfo); + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, + mTestableContext, + taskInfo, + /* applyStartTransactionOnDraw= */ true, + /* shouldSetTaskPositionAndCrop */ false); - verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any()); + // 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_postsViewHostCreation() { + public void relayout_fullscreenTask_appliesTransactionImmediately() { 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()); + verify(mMockTransaction).apply(); + verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any()); } @Test - public void relayout_freeformTask_createsViewHostImmediately() { + public void relayout_freeformTask_appliesTransactionOnDraw() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); @@ -564,36 +572,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { 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(mMockTransaction, never()).apply(); + verify(mMockWindowDecorViewHost).updateView(any(), any(), any(), eq(mMockTransaction)); } @Test @@ -766,6 +746,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { any(), any(), any(), + any(), openInBrowserCaptor.capture(), any(), any() @@ -793,6 +774,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { any(), any(), any(), + any(), openInBrowserCaptor.capture(), any(), any() @@ -843,6 +825,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { any(), any(), any(), + any(), closeClickListener.capture(), any() ); @@ -854,8 +837,10 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } 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 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { 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 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } 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 100abbbb8332..a84523112d9b 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 @@ class HandleMenuTest : ShellTestCase() { 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 6154391c5e97..7252b32efc6b 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.common.DisplayController; 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 @@ public class WindowDecorationTests extends ShellTestCase { @Mock private SurfaceControlViewHost mMockSurfaceControlViewHost; @Mock + private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier; + @Mock + private WindowDecorViewHost mMockWindowDecorViewHost; + @Mock private AttachedSurfaceControl mMockRootSurfaceControl; @Mock private TestView mMockView; @@ -167,6 +173,9 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { } @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 @@ public class WindowDecorationTests extends ShellTestCase { } @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 @@ public class WindowDecorationTests extends ShellTestCase { } @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 @@ public class WindowDecorationTests extends ShellTestCase { new MockObjectSupplier<>(mMockSurfaceControlTransactions, () -> mock(SurfaceControl.Transaction.class)), () -> mMockWindowContainerTransaction, () -> mMockTaskSurface, - mMockSurfaceControlViewHostFactory); + mMockSurfaceControlViewHostFactory, + mMockWindowDecorViewHostSupplier); } private class MockObjectSupplier<T> implements Supplier<T> { @@ -1020,16 +1042,20 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 000000000000..1b2ce9e4df36 --- /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 000000000000..c093675ee580 --- /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 5a45ad9085e7..8deac61e8baa 100644 --- a/libs/hwui/SkiaInterpolator.cpp +++ b/libs/hwui/SkiaInterpolator.cpp @@ -47,6 +47,8 @@ static inline Dot14 pin_and_convert(float x) { 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 @@ void SkiaInterpolatorBase::reset(int elemCount, int frameCount) { 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 @@ bool SkiaInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const 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 @@ float SkiaInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSe // 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 @@ int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, SkMSec 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 @@ int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, SkMSec 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 @@ SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T } 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 @@ void SkiaInterpolator::reset(int elemCount, int frameCount) { 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 @@ bool SkiaInterpolator::setKeyFrame(int index, SkMSec time, const float values[], 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 c80a9b4ae97f..000f1092eb17 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 @@ private: 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 @@ int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const // 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 @@ int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const 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 8c4b439d2a2b..6f65e9eb0495 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 jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmap 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 ae6ac4ce4ecc..6c82aa1ca27d 100644 --- a/libs/hwui/jni/GIFMovie.cpp +++ b/libs/hwui/jni/GIFMovie.cpp @@ -30,7 +30,7 @@ public: protected: virtual bool onGetInfo(Info*); - virtual bool onSetTime(SkMSec); + virtual bool onSetTime(Movie::MSec); virtual bool onGetBitmap(SkBitmap*); private: @@ -72,7 +72,7 @@ GIFMovie::~GIFMovie() 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 @@ bool GIFMovie::onGetInfo(Info* info) 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 @@ bool GIFMovie::onGetInfo(Info* info) 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 02113dd58ec8..d633d935f566 100644 --- a/libs/hwui/jni/Movie.h +++ b/libs/hwui/jni/Movie.h @@ -19,6 +19,8 @@ class SkStreamRewindable; 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 @@ public: */ static Movie* DecodeMemory(const void* data, size_t length); - SkMSec duration(); + MSec duration(); int width(); int height(); int isOpaque(); @@ -46,21 +48,21 @@ public: 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 @@ protected: 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 abb75fa99c94..a31a15f061b1 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 @@ void Movie::ensureInfo() memset(&fInfo, 0, sizeof(fInfo)); // failure } -SkMSec Movie::duration() +Movie::MSec Movie::duration() { this->ensureInfo(); return fInfo.fDuration; @@ -50,9 +50,9 @@ int Movie::isOpaque() 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 d03ceb471d6c..2414299321a9 100644 --- a/libs/hwui/libhwui.map.txt +++ b/libs/hwui/libhwui.map.txt @@ -13,6 +13,7 @@ LIBHWUI { # platform-only /* HWUI isn't current a module, so all of these are st 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 bbd91fc19ee5..dcf5c5b46478 100644 --- a/location/java/android/location/flags/location.aconfig +++ b/location/java/android/location/flags/location.aconfig @@ -116,4 +116,7 @@ flag { 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 880ec8fdef88..2b727445c797 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 5ca0fc9661c2..5d1153d93b4f 100644 --- a/media/tests/LoudnessCodecApiTest/Android.bp +++ b/media/tests/LoudnessCodecApiTest/Android.bp @@ -25,3 +25,10 @@ android_test { 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 346c87daec87..25c063d6ccd8 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -367,6 +367,7 @@ LIBANDROID_PLATFORM { 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 e91c7a9ecda8..095d7d1145ae 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 @@ using namespace std::chrono_literals; // 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 @@ struct AWorkDuration : public hal::WorkDuration {}; // 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 @@ private: std::shared_ptr<IHintManager> mHintManager; ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; + FMQWrapper mFMQWrapper; }; struct APerformanceHintSession { @@ -121,40 +174,57 @@ private: 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 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa if (preferredRateNanos <= 0) { preferredRateNanos = -1L; } - return new APerformanceHintManager(std::move(manager), preferredRateNanos); + return new APerformanceHintManager(manager, preferredRateNanos); } APerformanceHintSession* APerformanceHintManager::createSession( @@ -187,15 +257,20 @@ APerformanceHintSession* APerformanceHintManager::createSession( 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 @@ int64_t APerformanceHintManager::getPreferredRateNanos() const { 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 @@ APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> h 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 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano 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; } - ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos); - if (!ret.isOk()) { - ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__, - ret.getMessage()); - return EPIPE; + 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; + } } - 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 @@ int APerformanceHintSession::sendHint(SessionHint hint) { 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::reportActualWorkDuration(AWorkDuration* workDuratio 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 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor 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 AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration, } 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 608d5d8a923a..f6f1da1eed79 100644 --- a/native/android/tests/performance_hint/Android.bp +++ b/native/android/tests/performance_hint/Android.bp @@ -36,10 +36,13 @@ cc_test { 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 @@ cc_test { ], 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 d19fa98f1171..9de3a6f525e6 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 @@ class MockIHintManager : public IHintManager { 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 @@ public: (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 @@ public: } 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 @@ public: 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 @@ public: 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 @@ TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) { 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 @@ TEST_F(PerformanceHintTest, TestAWorkDuration) { 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 b997c35668d2..0cb85d8638b0 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -42,8 +42,6 @@ android_library { "SettingsLibIllustrationPreference", "SettingsLibLayoutPreference", "SettingsLibMainSwitchPreference", - "SettingsLibMetadata", - "SettingsLibPreference", "SettingsLibProfileSelector", "SettingsLibProgressBar", "SettingsLibRestrictedLockUtils", diff --git a/packages/SettingsLib/Graph/Android.bp b/packages/SettingsLib/Graph/Android.bp index e2ed1e448207..163b689d800b 100644 --- a/packages/SettingsLib/Graph/Android.bp +++ b/packages/SettingsLib/Graph/Android.bp @@ -4,7 +4,7 @@ package { filegroup { name: "SettingsLibGraph-srcs", - srcs: ["src/**/*"], + srcs: ["src/**/*.kt"], } android_library { @@ -14,8 +14,24 @@ android_library { ], 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 000000000000..e93d756d0285 --- /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 000000000000..04c29682c8d8 --- /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 000000000000..8c5d8778c96f --- /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 9231f40e2e78..000000000000 --- 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 9e4c1f60851a..000000000000 --- 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 000000000000..d9b9590f60e2 --- /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 000000000000..d7dae7771acd --- /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 000000000000..2c7209a48bbd --- /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 000000000000..fc48a7da8044 --- /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 000000000000..ea2c3a1b52db --- /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 000000000000..42772a4b5002 --- /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 000000000000..802141dae7ec --- /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 000000000000..4b7572b90b3f --- /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 000000000000..0bdae38a0a24 --- /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 000000000000..7ffefed239a4 --- /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 000000000000..795a920ba575 --- /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 000000000000..da9c955d5069 --- /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 000000000000..8b2deaf68786 --- /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 ffd28798d82f..83d657ef380d 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.SettingsPageProviderReposito 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 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { 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 index 5dd7cafb962a..6edd9173d7e5 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.compose.navigator 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 @@ object CardPageProvider : SettingsPageProvider { } @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 @@ object CardPageProvider : SettingsPageProvider { } @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 @@ object CardPageProvider : SettingsPageProvider { Text(text = "Abc") } } - SettingsCardContent { + SettingsBannerContent { Box( Modifier .fillMaxWidth() @@ -171,13 +171,13 @@ object CardPageProvider : SettingsPageProvider { } } - 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 654719d906a9..b1558cce718a 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.framework.theme.SettingsTheme 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 @@ object HomePageProvider : SettingsPageProvider { 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 000000000000..4ef258f24776 --- /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 000000000000..e3f4860ee764 --- /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 000000000000..31a1e9cd36a8 --- /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 index ffc7e86665dd..a8479b01a861 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.Test 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 @@ class SettingsCardTest { } @Test - fun settingsCard_textDisplayed() { + fun settingsBanner_textDisplayed() { composeTestRule.setContent { - SettingsCard( - CardModel( + SettingsBanner( + BannerModel( title = "", text = TEXT, ) @@ -69,13 +69,13 @@ class SettingsCardTest { } @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 @@ class SettingsCardTest { } @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 @@ class SettingsCardTest { } @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 @@ class SettingsCardTest { } @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 @@ class SettingsCardTest { } @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 index aba9d7be1e91..1080fdea9455 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.Test 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 @@ class SettingsCollapsibleCardTest { 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 @@ class SettingsCollapsibleCardTest { 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 34b597ba4486..79c3ff9ce989 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -139,3 +139,13 @@ flag { 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 4d771c0f8d71..feee89a51e7c 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 1e5833564d39..9d56c77b097b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -520,8 +520,6 @@ public class Utils { 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 c6eb9fddf2a7..6dab22454baf 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 @@ package com.android.settingslib.bluetooth; 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 @@ public class CsipDeviceManager { 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 @@ public class CsipDeviceManager { preferredMainDevice.refresh(); hasChanged = true; } + syncAudioSharingSourceIfNeeded(preferredMainDevice); } if (hasChanged) { log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: " @@ -384,6 +388,41 @@ public class CsipDeviceManager { 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 a0fe5d275b36..38183d5a01fd 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 @@ data class DeviceSettingItem( val className: String, val intentAction: String, val preferenceKey: String? = null, + val highlighted: Boolean = false, val extras: Bundle = Bundle.EMPTY, ) : Parcelable { @@ -47,6 +48,7 @@ data class DeviceSettingItem( writeString(packageName) writeString(className) writeString(intentAction) + writeBoolean(highlighted) writeString(preferenceKey) writeBundle(extras) } @@ -63,6 +65,7 @@ data class DeviceSettingItem( 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 4b67ef78c014..c8c7562c03f1 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 @@ public abstract class DeviceSettingPreference { 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 769b6e6796f9..29664f63d3b2 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 @@ class DeviceSettingRepositoryImpl( 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 08fb3fb8fb22..5958c30b079e 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 @@ data class DeviceSettingConfigModel( /** 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 @@ sealed interface DeviceSettingConfigItemModel { /** 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 79949248cd8a..000000000000 --- 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 000000000000..766cd438a811 --- /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 000000000000..548eb3fd4b8f --- /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 7467ee1c1a7c..d58add4bb5eb 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 7b2a284803a2..3cc111f6e099 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 @@ public class ZenMode implements Parcelable { 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 @@ public class ZenMode implements Parcelable { 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 698eb8159846..b180b69f1e07 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 @@ package com.android.settingslib.bluetooth; 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 @@ public class CsipDeviceManagerTest { 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 56e9b6c27925..86071bbef899 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 @@ class DeviceSettingItemTest { packageName = "package_name", className = "class_name", intentAction = "intent_action", + preferenceKey = "key1", + highlighted = true, extras = Bundle().apply { putString("key1", "value1") }, ) @@ -43,6 +45,7 @@ class DeviceSettingItemTest { 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 a0a2658b05d3..7f1729387a22 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 @@ class DeviceSettingsConfigTest { 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 000000000000..bc1ea6c42fa3 --- /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 000000000000..2501ae6769b6 --- /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 62401a124ad1..aca26ecce29a 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 @@ flag { 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 d39b5645109d..b491b5a146e1 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -223,6 +223,7 @@ public class SettingsBackupTest { 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 6399ffdfdf2f..082a58942059 100644 --- a/packages/Shell/tests/Android.bp +++ b/packages/Shell/tests/Android.bp @@ -26,3 +26,10 @@ android_test { 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 be4e9a14b043..f59eab001be9 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -934,9 +934,9 @@ android_robolectric_test { "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 000000000000..4324d463c276 --- /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 000000000000..3cbb688ce7ca --- /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 000000000000..31cca701ca9d --- /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 c14ee6208176..9d0b095ad4cc 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.annotations.VisibleForTesting 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 @@ constructor( contentBeforeFadeOutDelay = 0L, contentBeforeFadeOutDuration = 150L, contentAfterFadeInDelay = 150L, - contentAfterFadeInDuration = 183L + contentAfterFadeInDuration = 183L, ) /** @@ -147,7 +148,7 @@ constructor( 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 @@ constructor( 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 @@ constructor( RemoteAnimationAdapter( runner, TIMINGS.totalDuration, - TIMINGS.totalDuration - 150 /* statusBarTransitionDelay */ + TIMINGS.totalDuration - 150, /* statusBarTransitionDelay */ ) } else { null @@ -277,7 +278,7 @@ constructor( .registerRemoteAnimationForNextActivityStart( packageName, animationAdapter, - null /* launchCookie */ + null, /* launchCookie */ ) } catch (e: RemoteException) { Log.w(TAG, "Unable to register the remote animation", e) @@ -301,7 +302,7 @@ constructor( Log.i( TAG, "launchResult=$launchResult willAnimate=$willAnimate " + - "hideKeyguardWithAnimation=$hideKeyguardWithAnimation" + "hideKeyguardWithAnimation=$hideKeyguardWithAnimation", ) controller.callOnIntentStartedOnMainThread(willAnimate) @@ -328,7 +329,7 @@ constructor( Log.d( TAG, "Calling controller.onIntentStarted(willAnimate=$willAnimate) " + - "[controller=$this]" + "[controller=$this]", ) } this.onIntentStarted(willAnimate) @@ -350,7 +351,7 @@ constructor( 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 @@ constructor( */ private fun registerEphemeralReturnAnimation( launchController: Controller, - transitionRegister: TransitionRegister? + transitionRegister: TransitionRegister?, ) { if (!returnAnimationFrameworkLibrary()) return @@ -410,7 +411,7 @@ constructor( val transition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(returnRunner), - "${launchController.transitionCookie}_returnTransition" + "${launchController.transitionCookie}_returnTransition", ) transitionRegister?.register(filter, transition) @@ -508,7 +509,7 @@ constructor( 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 @@ constructor( Log.e( TAG, "Skipping animation as view $view is not attached to a ViewGroup", - Exception() + Exception(), ) return null } @@ -535,7 +536,7 @@ constructor( cujType, cookie, component, - returnCujType + returnCujType, ) } } @@ -646,7 +647,7 @@ constructor( val launchRemoteTransition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(createRunner(controller)), - "${cookie}_launchTransition" + "${cookie}_launchTransition", ) transitionRegister.register(launchFilter, launchRemoteTransition) @@ -668,7 +669,7 @@ constructor( val returnRemoteTransition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(createRunner(returnController)), - "${cookie}_returnTransition" + "${cookie}_returnTransition", ) transitionRegister.register(returnFilter, returnRemoteTransition) @@ -690,7 +691,7 @@ constructor( @VisibleForTesting inner class DelegatingAnimationCompletionListener( private val delegate: Listener?, - private val onAnimationComplete: () -> Unit + private val onAnimationComplete: () -> Unit, ) : Listener { var cancelled = false @@ -723,7 +724,7 @@ constructor( /** 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 @@ constructor( 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 @@ constructor( Log.wtf( TAG, "The remote animation was neither cancelled or started within " + - "$LONG_TRANSITION_TIMEOUT" + "$LONG_TRANSITION_TIMEOUT", ) } @@ -869,7 +870,7 @@ constructor( apps: Array<out RemoteAnimationTarget>?, wallpapers: Array<out RemoteAnimationTarget>?, nonApps: Array<out RemoteAnimationTarget>?, - callback: IRemoteAnimationFinishedCallback? + callback: IRemoteAnimationFinishedCallback?, ) { removeTimeouts() @@ -894,7 +895,7 @@ constructor( 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 @@ constructor( private fun startAnimation( window: RemoteAnimationTarget, navigationBar: RemoteAnimationTarget?, - iCallback: IRemoteAnimationFinishedCallback? + iCallback: IRemoteAnimationFinishedCallback?, ) { if (TransitionAnimator.DEBUG) { Log.d(TAG, "Remote animation started") @@ -983,12 +984,28 @@ constructor( 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 @@ constructor( ?: 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 @@ constructor( 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 @@ constructor( TAG, "Calling controller.onTransitionAnimationStart(" + "isExpandingFullyAbove=$isExpandingFullyAbove) " + - "[controller=$delegate]" + "[controller=$delegate]", ) } delegate.onTransitionAnimationStart(isExpandingFullyAbove) @@ -1050,7 +1062,7 @@ constructor( TAG, "Calling controller.onTransitionAnimationEnd(" + "isExpandingFullyAbove=$isExpandingFullyAbove) " + - "[controller=$delegate]" + "[controller=$delegate]", ) } delegate.onTransitionAnimationEnd(isExpandingFullyAbove) @@ -1059,7 +1071,7 @@ constructor( 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 @@ constructor( windowCropF.left.roundToInt(), windowCropF.top.roundToInt(), windowCropF.right.roundToInt(), - windowCropF.bottom.roundToInt() + windowCropF.bottom.roundToInt(), ) val windowAnimationDelay = @@ -1155,7 +1167,7 @@ constructor( TIMINGS, linearProgress, windowAnimationDelay, - windowAnimationDuration + windowAnimationDuration, ) // The alpha of the opening window. If it opens above the expandable, then it should @@ -1198,7 +1210,7 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( } /** 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 8e824e60d449..fc4cf1d1e21e 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.util.MathUtils 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 @@ class TransitionAnimator( 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 @@ class TransitionAnimator( "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 @@ class TransitionAnimator( 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 @@ class TransitionAnimator( 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 @@ class TransitionAnimator( 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 @@ class TransitionAnimator( val contentBeforeFadeOutInterpolator: Interpolator, /** The interpolator used when fading in the expanded content. */ - val contentAfterFadeInInterpolator: Interpolator + val contentAfterFadeInInterpolator: Interpolator, ) /** @@ -254,7 +276,7 @@ class TransitionAnimator( endState, windowBackgroundLayer, fadeWindowBackgroundLayer, - drawHole + drawHole, ) animator.start() @@ -271,7 +293,7 @@ class TransitionAnimator( endState: State, windowBackgroundLayer: GradientDrawable, fadeWindowBackgroundLayer: Boolean = true, - drawHole: Boolean = false + drawHole: Boolean = false, ): ValueAnimator { val state = controller.createAnimatorState() @@ -399,14 +421,14 @@ class TransitionAnimator( timings, linearProgress, timings.contentBeforeFadeOutDelay, - timings.contentBeforeFadeOutDuration + timings.contentBeforeFadeOutDuration, ) < 1 } else { getProgress( timings, linearProgress, timings.contentAfterFadeInDelay, - timings.contentAfterFadeInDuration + timings.contentAfterFadeInDuration, ) > 0 } @@ -427,7 +449,7 @@ class TransitionAnimator( ViewRootSync.synchronizeNextDraw( transitionContainer, openingWindowSyncView, - then = {} + then = {}, ) } else if ( !controller.isLaunching && @@ -446,7 +468,7 @@ class TransitionAnimator( ViewRootSync.synchronizeNextDraw( openingWindowSyncView, transitionContainer, - then = {} + then = {}, ) } @@ -464,7 +486,7 @@ class TransitionAnimator( container, fadeWindowBackgroundLayer, drawHole, - controller.isLaunching + controller.isLaunching, ) controller.onTransitionAnimationProgress(state, progress, linearProgress) } @@ -488,7 +510,7 @@ class TransitionAnimator( transitionContainer: View, fadeWindowBackgroundLayer: Boolean, drawHole: Boolean, - isLaunching: Boolean + isLaunching: Boolean, ) { // Update position. transitionContainer.getLocationOnScreen(transitionContainerLocation) @@ -496,7 +518,7 @@ class TransitionAnimator( 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 @@ class TransitionAnimator( timings, linearProgress, timings.contentBeforeFadeOutDelay, - timings.contentBeforeFadeOutDuration + timings.contentBeforeFadeOutDuration, ) if (isLaunching) { @@ -531,7 +553,7 @@ class TransitionAnimator( timings, linearProgress, timings.contentAfterFadeInDelay, - timings.contentAfterFadeInDuration + timings.contentAfterFadeInDuration, ) val alpha = 1 - @@ -561,7 +583,7 @@ class TransitionAnimator( timings, linearProgress, timings.contentAfterFadeInDelay, - timings.contentAfterFadeInDuration + timings.contentAfterFadeInDuration, ) val alpha = 1 - 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 34eafdee9c76..d326f00d869e 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 @@ private fun UserSwitcher( 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 480e4e47ecf0..489e24e8b328 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.focus.focusRequester 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.bouncer.ui.viewmodel.PinBouncerViewModel 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 @@ fun PinPad( 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 @@ fun PinPad( onClicked = viewModel::onPinButtonClicked, scaling = buttonScaleAnimatables[index]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, + onPointerDown = viewModel::onDigitButtonDown, ) } @@ -125,6 +129,7 @@ fun PinPad( onLongPressed = viewModel::onBackspaceButtonLongPressed, appearance = backspaceButtonAppearance, scaling = buttonScaleAnimatables[9]::value, + elementId = "delete_button" ) DigitButton( @@ -133,6 +138,7 @@ fun PinPad( onClicked = viewModel::onPinButtonClicked, scaling = buttonScaleAnimatables[10]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, + onPointerDown = viewModel::onDigitButtonDown ) ActionButton( @@ -146,6 +152,7 @@ fun PinPad( onClicked = viewModel::onAuthenticateButtonClicked, appearance = confirmButtonAppearance, scaling = buttonScaleAnimatables[11]::value, + elementId = "key_enter" ) } } @@ -155,6 +162,7 @@ private fun DigitButton( digit: Int, isInputEnabled: Boolean, onClicked: (Int) -> Unit, + onPointerDown: () -> Unit, scaling: () -> Float, isAnimationEnabled: Boolean, ) { @@ -164,6 +172,7 @@ private fun DigitButton( 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 @@ private fun ActionButton( icon: Icon, isInputEnabled: Boolean, onClicked: () -> Unit, + elementId: String, onLongPressed: (() -> Unit)? = null, appearance: ActionButtonAppearance, scaling: () -> Float, @@ -211,6 +221,7 @@ private fun ActionButton( backgroundColor = backgroundColor, foregroundColor = foregroundColor, isAnimationEnabled = true, + elementId = elementId, modifier = Modifier.graphicsLayer { alpha = hiddenAlpha @@ -234,7 +245,9 @@ private fun PinPadButton( 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 @@ private fun PinPadButton( .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 a4dc8fc565f6..557257d6bdc0 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 @@ object AllElements : ElementMatcher { 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 efe0f2e815da..f4d1242098f9 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.runtime.snapshotFlow 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.SmartspaceAppWidgetHostView 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 @@ private fun WidgetContent( 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 @@ private fun WidgetContent( Modifier.selectable( selected = isSelected, onClick = { viewModel.setSelectedKey(model.key) }, - interactionSource = remember { MutableInteractionSource() }, + interactionSource = interactionSource, indication = null, ) } else { @@ -1172,6 +1184,8 @@ private fun WidgetContent( 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 1f4cd0473086..000000000000 --- 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 671b0128b621..a6d5c1cef81f 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.qs.ui.adapter.QSSceneAdapter.State.UnsquishingQS 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 @@ object QuickSettings { 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 @@ private fun SceneScope.stateForQuickSettingsContent( } } is TransitionState.Transition.OverlayTransition -> - TODO("b/359173565: Handle overlay transitions") + error("Bad transition for QuickSettings scene: overlays not supported") } } @@ -172,7 +168,7 @@ fun SceneScope.QuickSettings( val height = heightProvider().coerceAtLeast(0) layout(placeable.width, height) { placeable.placeRelative(0, 0) } - } + }, ) { content { QuickSettingsContent(qsSceneAdapter = qsSceneAdapter, contentState) } } @@ -225,7 +221,7 @@ private fun QuickSettingsContent( 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 d34295ea1d22..fa92bef34f38 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.layout.layoutId 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 @@ constructor( } @Composable - override fun SceneScope.Content( - modifier: Modifier, - ) { + override fun SceneScope.Content(modifier: Modifier) { QuickSettingsScene( notificationStackScrollView = notificationStackScrollView.get(), viewModelFactory = contentViewModelFactory, @@ -199,13 +198,17 @@ private fun SceneScope.QuickSettingsScene( 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 @@ private fun SceneScope.QuickSettingsScene( // 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 @@ private fun SceneScope.QuickSettingsScene( 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 @@ private fun SceneScope.QuickSettingsScene( 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 @@ private fun SceneScope.QuickSettingsScene( 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 @@ private fun SceneScope.QuickSettingsScene( Column( modifier = - shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view"), + shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view") ) { when (LocalWindowSizeClass.current.widthSizeClass) { WindowWidthSizeClass.Compact -> @@ -345,7 +339,7 @@ private fun SceneScope.QuickSettingsScene( expandFrom = Alignment.Top, ) + slideInVertically( - animationSpec = tween(customizingAnimationDuration), + animationSpec = tween(customizingAnimationDuration) ) + fadeIn(tween(customizingAnimationDuration)), exit = @@ -354,7 +348,7 @@ private fun SceneScope.QuickSettingsScene( shrinkTowards = Alignment.Top, ) + slideOutVertically( - animationSpec = tween(customizingAnimationDuration), + animationSpec = tween(customizingAnimationDuration) ) + fadeOut(tween(customizingAnimationDuration)), ) { @@ -382,7 +376,7 @@ private fun SceneScope.QuickSettingsScene( viewModel.qsSceneAdapter, { viewModel.qsSceneAdapter.qsHeight }, isSplitShade = false, - modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS) + modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS), ) MediaCarousel( @@ -400,13 +394,12 @@ private fun SceneScope.QuickSettingsScene( { 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 @@ private fun SceneScope.QuickSettingsScene( 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 @@ private fun SceneScope.QuickSettingsScene( 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 e27c7e29ba50..000000000000 --- 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 f660808fb015..f64d0ed31287 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.TransitionKey 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.lockscreenToGoneTran 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 @@ val SceneContainerTransitions = transitions { 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 @@ val SceneContainerTransitions = transitions { 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/FromNotificationsShadeToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt new file mode 100644 index 000000000000..24f285e81da2 --- /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 9d13647bc43f..55fa6ad94ed3 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.OverlayShade 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 @@ fun TransitionBuilder.toQuickSettingsShadeTransition( ) 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 89222246b4eb..b85523bc1694 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 @@ fun SceneScope.OverlayShade( 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 @@ private fun SceneScope.Scrim( } @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 @@ private fun SceneScope.Panel( .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 @@ private fun Modifier.panelPadding(): Modifier { systemBars.asPaddingValues(), displayCutout.asPaddingValues(), waterfall.asPaddingValues(), - contentPadding + contentPadding, ) return if (widthSizeClass == WindowWidthSizeClass.Compact) { @@ -156,14 +147,19 @@ private fun combinePaddings(vararg paddingValues: PaddingValues): PaddingValues 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 df22264269ea..8a59e204eb23 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.layout.layoutId 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 @@ constructor( 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 @@ private fun SceneScope.ShadeScene( 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 @@ private fun SceneScope.SingleShade( 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 @@ private fun SceneScope.SingleShade( } else { cutoutInsets } - } + }, ) } @@ -337,7 +344,7 @@ private fun SceneScope.SingleShade( 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 @@ private fun SceneScope.SingleShade( .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 @@ private fun SceneScope.SplitShade( 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 @@ private fun SceneScope.SplitShade( ) ) - Column( - modifier = Modifier.fillMaxSize(), - ) { + Column(modifier = Modifier.fillMaxSize()) { CollapsedShadeHeader( viewModelFactory = viewModel.shadeHeaderViewModelFactory, createTintedIconManager = createTintedIconManager, @@ -526,9 +523,7 @@ private fun SceneScope.SplitShade( statusBarIconController = statusBarIconController, modifier = Modifier.then(brightnessMirrorShowingModifier) - .padding( - horizontal = { unfoldTranslationXForStartSide.roundToInt() }, - ) + .padding(horizontal = { unfoldTranslationXForStartSide.roundToInt() }), ) Row(modifier = Modifier.fillMaxWidth().weight(1f)) { @@ -536,14 +531,14 @@ private fun SceneScope.SplitShade( 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 @@ private fun SceneScope.SplitShade( .thenIf(!isCustomizerShowing) { Modifier.verticalScroll( quickSettingsScrollState, - enabled = isScrollable + enabled = isScrollable, ) .clipScrollableContainer(Orientation.Horizontal) } @@ -619,16 +614,16 @@ private fun SceneScope.SplitShade( .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 @@ private fun SceneScope.ShadeMediaCarousel( 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 5a084dbd9905..ebe1df4bf55f 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 @@ private fun shouldPlaceElement( 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 f9a9eeb0d34f..2e7488b9cccb 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 @@ open class ElementKey( * 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 1f26b71cf3e5..6a5b7e103dbb 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 @@ internal fun Element( 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 @@ internal fun MovableElement( "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 30eb302b3bcb..077927dfe0a2 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 @@ sealed interface ObservableTransitionState { 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 interface ObservableTransitionState { sealed class Transition( val fromContent: ContentKey, val toContent: ContentKey, - val currentOverlays: Flow<Set<OverlayKey>>, val progress: Flow<Float>, /** @@ -105,7 +105,7 @@ sealed interface ObservableTransitionState { 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 @@ sealed interface ObservableTransitionState { 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 @@ sealed interface ObservableTransitionState { 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 @@ sealed interface ObservableTransitionState { previewProgress: Flow<Float>, isInPreviewStage: Flow<Boolean>, ) : - Transition( + OverlayTransition( fromContent, toContent, + currentScene, currentOverlays, progress, isInitiatedByUserInput, @@ -151,7 +176,7 @@ sealed interface ObservableTransitionState { 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 @@ sealed interface ObservableTransitionState { 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 f20548b1f81b..cec888380513 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 @@ interface SceneTransitionLayoutScope { * 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 @@ interface SceneTransitionLayoutScope { 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 fe052344023c..65c404387734 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 @@ internal class SceneTransitionLayoutImpl( key: OverlayKey, userActions: Map<UserAction, UserActionResult>, alignment: Alignment, + isModal: Boolean, content: @Composable (ContentScope.() -> Unit), ) { overlaysDefined = true @@ -266,6 +271,7 @@ internal class SceneTransitionLayoutImpl( overlay.zIndex = zIndex overlay.userActions = resolvedUserActions overlay.alignment = alignment + overlay.isModal = isModal } else { // New overlay. overlays[key] = @@ -276,6 +282,7 @@ internal class SceneTransitionLayoutImpl( resolvedUserActions, zIndex, alignment, + isModal, ) } @@ -399,12 +406,30 @@ internal class SceneTransitionLayoutImpl( 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 dbff8a4f7f45..2e8fc14517c4 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 @@ sealed interface MutableSceneTransitionLayoutState : SceneTransitionLayoutState 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 @@ internal class MutableSceneTransitionLayoutStateImpl( ) } - /** - * 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 @@ internal class MutableSceneTransitionLayoutStateImpl( } } - /** - * 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 ccec9e834385..d4de559cef43 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 @@ internal class Overlay( 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 364c2036e02d..d6751ae9ff81 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 @@ sealed interface TransitionState { } /** 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 @@ sealed interface TransitionState { * * 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 20a1e3c02dd0..1eed54ed3019 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.assertIsDisplayed 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 @@ class ElementTest { 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 7c9e9ce7c031..e57702c045c6 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 @@ class MovableElementTest { 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 @@ class MovableElementTest { 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 ffed15b457f9..cae6617cb11b 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 @@ package com.android.compose.animation.scene 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.setValue 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 @@ class OverlayTest { .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 de55e2fb7657..ea6f208d6bb9 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.TransitionBuilder 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 062d351100d6..a1d944b403d3 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.SysuiTestCase 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 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { @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 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { fakeFeatureFlags, mSelectedUserInteractor, keyguardKeyboardInteractor, - null, - mUserActivityNotifier + kosmos.bouncerHapticPlayer, + mUserActivityNotifier, ) } @@ -194,7 +197,7 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { 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 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { 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 bb152086cdab..d63e728cf443 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.FalsingCollector 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 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { @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 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { 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 1076d9089d79..4d1660e71c0a 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.internal.widget.LockPatternUtils; 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 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { 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 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { 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 43db5a70849f..ab59051dcd4a 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.dreams.DreamOverlayStatusBarItemsProvider; 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.junit.runner.RunWith; 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 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase { DreamOverlayStateController mDreamOverlayStateController; @Mock UserTracker mUserTracker; + @Mock + PrivacyItemController mPrivacyItemController; LogBuffer mLogBuffer = FakeLogBuffer.Factory.Companion.create(); @@ -146,6 +153,7 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase { mDreamOverlayStateController, mUserTracker, mKosmos.getWifiInteractor(), + mPrivacyItemController, mKosmos.getCommunalSceneInteractor(), mLogBuffer); mController.onInit(); @@ -160,6 +168,7 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase { verify(mDreamOverlayNotificationCountProvider).addCallback(any()); verify(mDreamOverlayStatusBarItemsProvider).addCallback(any()); verify(mDreamOverlayStateController).addCallback(any()); + verify(mPrivacyItemController).addCallback(any()); } @Test @@ -172,6 +181,52 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase { } @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 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase { 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 8d82e972bdaa..2ee4aee2abab 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.data.repository.fakeAuthenticationRep 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.android.systemui.testKosmos 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 @@ class PinBouncerViewModelTest : SysuiTestCase() { 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 @@ class PinBouncerViewModelTest : SysuiTestCase() { 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 777ddab4e259..b96e40f43318 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { CommunalContentSize.THIRD, CommunalContentSize.THIRD, CommunalContentSize.THIRD, - ) + ), ) @Test - fun smartspace_dynamicSizing_fourCards_oneFullAndThreeThirdSize() = + fun smartspace_dynamicSizing_fourCards_threeThirdSizeAndOneFullSize() = testSmartspaceDynamicSizing( totalTargets = 4, expectedSizes = listOf( - CommunalContentSize.FULL, CommunalContentSize.THIRD, CommunalContentSize.THIRD, CommunalContentSize.THIRD, - ) + CommunalContentSize.FULL, + ), ) @Test - fun smartspace_dynamicSizing_fiveCards_twoHalfAndThreeThirdSize() = + fun smartspace_dynamicSizing_fiveCards_threeThirdAndTwoHalfSize() = testSmartspaceDynamicSizing( totalTargets = 5, expectedSizes = listOf( - CommunalContentSize.HALF, - CommunalContentSize.HALF, CommunalContentSize.THIRD, CommunalContentSize.THIRD, CommunalContentSize.THIRD, - ) + CommunalContentSize.HALF, + CommunalContentSize.HALF, + ), ) @Test @@ -335,7 +325,7 @@ class CommunalInteractorTest : SysuiTestCase() { CommunalContentSize.THIRD, CommunalContentSize.THIRD, CommunalContentSize.THIRD, - ) + ), ) private fun testSmartspaceDynamicSizing( @@ -355,7 +345,7 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { // 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 @@ class CommunalInteractorTest : SysuiTestCase() { } @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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { // 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 @@ class CommunalInteractorTest : SysuiTestCase() { // 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { setKeyguardFeaturesDisabled( USER_INFO_WORK, - DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE + DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE, ) // Widgets under work profile are available. @@ -958,7 +955,7 @@ class CommunalInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, - testScope + testScope, ) assertThat(showCommunalFromOccluded).isTrue() @@ -974,7 +971,7 @@ class CommunalInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.OCCLUDED, - testScope + testScope, ) assertThat(showCommunalFromOccluded).isFalse() @@ -990,7 +987,7 @@ class CommunalInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED, - testScope + testScope, ) runCurrent() kosmos.setCommunalAvailable(false) @@ -1008,13 +1005,13 @@ class CommunalInteractorTest : SysuiTestCase() { 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 @@ class CommunalInteractorTest : SysuiTestCase() { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.DREAMING, to = KeyguardState.OCCLUDED, - testScope + testScope, ) assertThat(showCommunalFromOccluded).isTrue() @@ -1040,7 +1037,7 @@ class CommunalInteractorTest : SysuiTestCase() { 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 dfb75cae6ecd..6a9b9beaa614 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.anyOrNull 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 @@ class CommunalSceneInteractorTest : SysuiTestCase() { 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 @@ class CommunalSceneInteractorTest : SysuiTestCase() { assertThat(currentScene).isEqualTo(CommunalScenes.Communal) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun changeScene_callsSceneStateProcessor() = testScope.runTest { @@ -78,6 +99,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { verify(callback).onSceneAboutToChange(CommunalScenes.Communal, null) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun changeScene_doesNotCallSceneStateProcessorForDuplicateState() = testScope.runTest { @@ -93,6 +115,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { verify(callback, never()).onSceneAboutToChange(any(), anyOrNull()) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun snapToScene() = testScope.runTest { @@ -104,6 +127,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { } @OptIn(ExperimentalCoroutinesApi::class) + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun snapToSceneWithDelay() = testScope.runTest { @@ -119,30 +143,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { 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 @@ class CommunalSceneInteractorTest : SysuiTestCase() { .isEqualTo(CommunalTransitionProgressModel.Idle(CommunalScenes.Communal)) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun transitionProgress_transitioningAwayFromTrackedScene() = testScope.runTest { @@ -201,6 +203,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { .isEqualTo(CommunalTransitionProgressModel.Idle(CommunalScenes.Communal)) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun transitionProgress_transitioningToTrackedScene() = testScope.runTest { @@ -238,6 +241,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { .isEqualTo(CommunalTransitionProgressModel.Idle(CommunalScenes.Communal)) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun isIdleOnCommunal() = testScope.runTest { @@ -265,6 +269,7 @@ class CommunalSceneInteractorTest : SysuiTestCase() { assertThat(isIdleOnCommunal).isEqualTo(false) } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun isCommunalVisible() = testScope.runTest { @@ -304,4 +309,206 @@ class CommunalSceneInteractorTest : SysuiTestCase() { ) 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 b3a12a69d1af..1e79112eefe3 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.ext.junit.runners.AndroidJUnit4 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 @@ class CommunalAppWidgetHostTest : SysuiTestCase() { 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 780d3576c5e4..09daa51a3b37 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.communalSettingsInteracto 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 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { 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 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { } @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 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { TransitionStep( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB, - ) + ), ) // Shade not expanded. if (!SceneContainerFlag.isEnabled) shadeTestUtil.setLockscreenShadeExpansion(0f) @@ -550,8 +629,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { stateTransition = TransitionStep( from = KeyguardState.DREAMING, - to = KeyguardState.GLANCEABLE_HUB, - ) + to = KeyguardState.GLANCEABLE_HUB + ), ) // Then flow is not frozen @@ -570,8 +649,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { stateTransition = TransitionStep( from = KeyguardState.GLANCEABLE_HUB, - to = KeyguardState.OCCLUDED, - ) + to = KeyguardState.OCCLUDED + ), ) // Then flow is not frozen @@ -595,7 +674,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { TransitionStep( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB, - ) + ), ) // Then flow is not frozen @@ -614,7 +693,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { to = KeyguardState.OCCLUDED, transitionState = TransitionState.STARTED, value = 0f, - ) + ), ) // Then flow is frozen @@ -629,7 +708,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { to = KeyguardState.OCCLUDED, transitionState = TransitionState.FINISHED, value = 1f, - ) + ), ) // Then flow is not frozen @@ -658,8 +737,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { 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 index f029847161d1..f029847161d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt +++ b/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 index 69fab5675e7f..69fab5675e7f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt +++ b/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 index 6d6c6efff13a..6d6c6efff13a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt +++ b/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 index 4da988a27cd5..4da988a27cd5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt +++ b/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 index 9d440c353d04..9d440c353d04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt +++ b/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 index 4793a52f3497..4793a52f3497 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt +++ b/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 index 6b0de92711b9..6b0de92711b9 100644 --- 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 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 index 6fd866066879..6fd866066879 100644 --- 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 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 index 295a626d2028..295a626d2028 100644 --- 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 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 index 6022d9cfcbfd..6022d9cfcbfd 100644 --- 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 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 index 2b7e7adbe022..2b7e7adbe022 100644 --- 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 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 3253edfb5fca..d90d58b8d25c 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 @@ package com.android.systemui.deviceentry.domain.interactor 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.data.repository.fakeTrustRepository 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 @@ class DeviceEntryInteractorTest : SysuiTestCase() { 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 @@ class DeviceEntryInteractorTest : SysuiTestCase() { 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 index d5839b502625..d5839b502625 100644 --- 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 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 index 77337d36a6b1..77337d36a6b1 100644 --- 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 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 index c39c3fe5f527..c39c3fe5f527 100644 --- 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 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 index 82ad30ecfbdd..82ad30ecfbdd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt +++ b/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 index 64ff5f73bd4d..64ff5f73bd4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt +++ b/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 index 3f5b9a35d3a5..3f5b9a35d3a5 100644 --- 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 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 index d79db5cc32eb..d79db5cc32eb 100644 --- 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 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 index a2b50fd2ec17..a2b50fd2ec17 100644 --- 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 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 index 8105bc8ae6a0..8105bc8ae6a0 100644 --- 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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java index e1dc6966092e..e1dc6966092e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java +++ b/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 index 20756c5e4015..20756c5e4015 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java +++ b/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 index 364b5d9be2b3..364b5d9be2b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/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 index 8c125f833b41..8c125f833b41 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java +++ b/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 index 299c38481b03..299c38481b03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java +++ b/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 index f55c2b77ca0f..f55c2b77ca0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java +++ b/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 index fad52e090c69..fad52e090c69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java +++ b/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 index 0d6a9ceece5c..0d6a9ceece5c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java +++ b/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 index 69e74d841919..69e74d841919 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java +++ b/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 index 4253c766e62f..4253c766e62f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java +++ b/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 index 597629219634..597629219634 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt +++ b/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 index f331060db43e..f331060db43e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt +++ b/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 index d09928b25084..d09928b25084 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt +++ b/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 index 0cd2b9f03475..0cd2b9f03475 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt +++ b/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 index ae6b337a3fa0..ae6b337a3fa0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt +++ b/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 25c533685ba7..64915fbf551f 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 @@ class KeyboardTouchpadEduInteractorTest : SysuiTestCase() { .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 index 0457100e0294..0457100e0294 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java +++ b/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 index 9f238e64ce7e..9f238e64ce7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt +++ b/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 index 3388a785a26a..3388a785a26a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt +++ b/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 index ad8bedb22d3b..ad8bedb22d3b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt +++ b/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 index dd56fa6be2d7..dd56fa6be2d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt +++ b/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 index 0ae59bbf47fe..0ae59bbf47fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt +++ b/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 index 593de37e0d6d..593de37e0d6d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt +++ b/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 index 46b4c4b80481..46b4c4b80481 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt +++ b/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 index 0f727cb8505c..0f727cb8505c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt +++ b/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 index 1ab945adb54f..1ab945adb54f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt +++ b/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 index df03882b649c..df03882b649c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt +++ b/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 index d1082bdca76b..d1082bdca76b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt +++ b/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 index 008c68d0631a..008c68d0631a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt +++ b/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 index 87dd9b229598..87dd9b229598 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java +++ b/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 index ea0f4d247a47..ea0f4d247a47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java +++ b/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 index a10457f704ec..a10457f704ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java +++ b/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 index 73509e2da520..73509e2da520 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java +++ b/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 index e437c10c7b73..e437c10c7b73 100644 --- 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 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 index 9275512009b2..9275512009b2 100644 --- 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 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 index 9deabc76065c..9deabc76065c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt +++ b/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 index 1d96c4d67c77..1d96c4d67c77 100644 --- 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 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 index f2e43fcb8e2c..f2e43fcb8e2c 100644 --- 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 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 index 9da68853a5aa..9da68853a5aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt +++ b/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 index 945f95385db2..945f95385db2 100644 --- 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 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 index 650f9dc7f104..650f9dc7f104 100644 --- 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 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 index 0c716137f434..0c716137f434 100644 --- 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 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 index 64cd09128373..64cd09128373 100644 --- 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 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 index 47261a935725..47261a935725 100644 --- 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 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 index 361e768a5b51..361e768a5b51 100644 --- 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 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 index 2735d2f03e6a..2735d2f03e6a 100644 --- 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 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 index 0b4e6a289f0e..0b4e6a289f0e 100644 --- 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 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 index 5d592087527c..5d592087527c 100644 --- 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 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 index 4d112e93013a..4d112e93013a 100644 --- 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 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 index 715d907b7372..715d907b7372 100644 --- 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 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 index c9c39b3ebf66..c9c39b3ebf66 100644 --- 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 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 index f37306276848..f37306276848 100644 --- 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 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 index af00a48d571b..af00a48d571b 100644 --- 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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java index a00cabc71a0c..a00cabc71a0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java +++ b/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 index 925ace26871f..925ace26871f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java +++ b/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 index 325bae15b18e..325bae15b18e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java +++ b/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 index 909acca12551..909acca12551 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/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 index e251ab50e3c7..e251ab50e3c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +++ b/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 index 99ff2d405c6f..99ff2d405c6f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java +++ b/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 index a9f7d0005624..a9f7d0005624 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java +++ b/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 index d435a4708b0a..d435a4708b0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt +++ b/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 index 47bf653c699c..47bf653c699c 100644 --- 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 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 index bbe45c1b3cd9..bbe45c1b3cd9 100644 --- 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 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 index bed959f1a3f0..bed959f1a3f0 100644 --- 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 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 index 0bd541c7a704..0bd541c7a704 100644 --- 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 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 index 2a2a82d53671..2a2a82d53671 100644 --- 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 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 index 1ec78742f0dd..1ec78742f0dd 100644 --- 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 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 index 14f2d654a031..14f2d654a031 100644 --- 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 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 index ea5a41f6fd5c..ea5a41f6fd5c 100644 --- 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 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 index 59f16d70fab5..59f16d70fab5 100644 --- 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 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 index 1981a2d612e4..41cc953cd1c2 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.authentication.shared.model.AuthenticationMethodMode 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.Idle 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 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { 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 index fabed03bc18c..fabed03bc18c 100644 --- 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 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 index 13f30f560cdf..13f30f560cdf 100644 --- 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 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 index c9871f1e4e1e..c9871f1e4e1e 100644 --- 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 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 index 7e249e8c179d..7e249e8c179d 100644 --- 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 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 index d77519d4b755..d77519d4b755 100644 --- 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 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 index c4eabd84e031..c4eabd84e031 100644 --- 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 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 index 0cfc20d7bbd8..0cfc20d7bbd8 100644 --- 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 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 index 040d3b8f09cb..040d3b8f09cb 100644 --- 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 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 index 9055495b9f23..9055495b9f23 100644 --- 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 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 index baa8ed73d7fb..baa8ed73d7fb 100644 --- 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 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 index 9fab0d9065b6..9fab0d9065b6 100644 --- 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 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 index 10f7128af43c..10f7128af43c 100644 --- 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 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 index 1c99eff0d328..1c99eff0d328 100644 --- 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 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 index 844a166be47b..844a166be47b 100644 --- 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 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 index c1bd37811787..c1bd37811787 100644 --- 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 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 index 129752e4f106..129752e4f106 100644 --- 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 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 index 17e1b53a3ba9..17e1b53a3ba9 100644 --- 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 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 3b2b12c4363d..2fd94e2016aa 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 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() } @Test + @DisableSceneContainer fun alpha_idleOnHub_isZero() = testScope.runTest { val alpha by collectLastValue(underTest.alpha(viewState)) @@ -506,6 +507,46 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() @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 index 2cb7e6523fd2..2cb7e6523fd2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt +++ b/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 index fd0ff9b38eec..fd0ff9b38eec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt +++ b/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 index 1abb441439fe..1abb441439fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt +++ b/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 index 2ba670ceb76a..2ba670ceb76a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt +++ b/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 index 73f724e7daef..73f724e7daef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt +++ b/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 index 732bef1f9803..732bef1f9803 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java +++ b/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 index d2e6dad8ed8d..d2e6dad8ed8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/core/LoggerTest.kt +++ b/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 index aa4a6d17123c..aa4a6d17123c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt +++ b/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 index a5f50af55a4b..a5f50af55a4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt +++ b/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 index 471c4615ef0a..471c4615ef0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt +++ b/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 index 8d608111744e..8d608111744e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt +++ b/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 index 4e976d0597cf..4e976d0597cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt +++ b/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 index 1d4b0903b579..1d4b0903b579 100644 --- 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 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 index 868145d1403a..868145d1403a 100644 --- 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 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 index 4e14fec8408f..4e14fec8408f 100644 --- 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 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 index 2f95936a576f..2f95936a576f 100644 --- 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 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 index d073cf1ac9db..d073cf1ac9db 100644 --- 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 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 index cdb060cee645..cdb060cee645 100644 --- 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 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 index bb9d20f88aa3..bb9d20f88aa3 100644 --- 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 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 index 50ae25ccfc00..50ae25ccfc00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java +++ b/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 index 8e9a1f9d52f5..8e9a1f9d52f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java +++ b/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 index a49819e5e7cc..a49819e5e7cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java +++ b/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 index 64acc5965d45..64acc5965d45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt +++ b/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 index b9aa02967acc..b9aa02967acc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt +++ b/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 index 293f66b2e182..293f66b2e182 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java +++ b/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 index 77807bf7915b..77807bf7915b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +++ b/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 index ab5c893644b0..ab5c893644b0 100644 --- 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 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 index 02123ba3ba02..02123ba3ba02 100644 --- 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 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 index cee71b5266a0..cee71b5266a0 100644 --- 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 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 index 352443a99acc..352443a99acc 100644 --- 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 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 index af8b3edf38c8..af8b3edf38c8 100644 --- 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 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 index 30b578a77e96..30b578a77e96 100644 --- 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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt index 62382570a2b1..62382570a2b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt +++ b/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 index 22bdfe8f3cb3..22bdfe8f3cb3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt +++ b/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 index 9797c8c5b538..9797c8c5b538 100644 --- 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 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 index a0cd835b4ec1..a0cd835b4ec1 100644 --- 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 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 index 3e3aa4f079f7..3e3aa4f079f7 100644 --- 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 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 index 69b7b2bfcf8c..69b7b2bfcf8c 100644 --- 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 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 index 55e52b780488..55e52b780488 100644 --- 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 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 index cc722aa40a1e..cc722aa40a1e 100644 --- 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 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 index 785d5a8e6184..785d5a8e6184 100644 --- 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 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 index ea5603d71e13..ea5603d71e13 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt +++ b/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 index 04ef1be9c057..04ef1be9c057 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt +++ b/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 index 6495b66cc148..6495b66cc148 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt +++ b/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 index d3ce871994f6..d3ce871994f6 100644 --- 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 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 index ce2b9830951b..ce2b9830951b 100644 --- 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 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 index 7fe55b85fcd8..7fe55b85fcd8 100644 --- 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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt index a3be9e35b912..a3be9e35b912 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt +++ b/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 index 9a78bd93f424..9a78bd93f424 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java +++ b/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 index e81e42b99442..e81e42b99442 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt +++ b/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 f6865f137071..642d9a0b1e9d 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.ext.junit.runners.AndroidJUnit4 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.flags.EnableSceneContainer 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 @@ class NotificationsShadeOverlayActionsViewModelTest : SysuiTestCase() { 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 @@ class NotificationsShadeOverlayActionsViewModelTest : SysuiTestCase() { 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 b54fd86779e6..75b090c4034b 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.anyOrNull 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 762941d70389..fd1c043f1a29 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.ext.junit.runners.AndroidJUnit4 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.flags.EnableSceneContainer 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 @@ class QuickSettingsShadeOverlayActionsViewModelTest : SysuiTestCase() { 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 @@ class QuickSettingsShadeOverlayActionsViewModelTest : SysuiTestCase() { } @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) + + 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 6986cf8ee7dc..62b6391ca54c 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.domain.interactor.keyguardEnabledInteractor 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.domain.startable.sceneContainerStartable 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 @@ class QuickSettingsUserActionsViewModelTest : SysuiTestCase() { 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 @@ class QuickSettingsUserActionsViewModelTest : SysuiTestCase() { 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 @@ class QuickSettingsUserActionsViewModelTest : SysuiTestCase() { 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 @@ class QuickSettingsUserActionsViewModelTest : SysuiTestCase() { 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 @@ class QuickSettingsUserActionsViewModelTest : SysuiTestCase() { 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 @@ class QuickSettingsUserActionsViewModelTest : SysuiTestCase() { 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 2d42c4247ab7..a0cafcbd5ad1 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { (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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { kosmos.emulatePendingTransitionProgress(expectedVisible = true) kosmos.enterSimPin( authMethodAfterSimUnlock = AuthenticationMethodModel.None, - enableLockscreen = false + enableLockscreen = false, ) kosmos.assertCurrentScene(Scenes.Gone) @@ -434,7 +428,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { /** 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { fakeSceneDataSource.pause() enterPin() - emulatePendingTransitionProgress( - expectedVisible = false, - ) + emulatePendingTransitionProgress(expectedVisible = false) } /** @@ -645,9 +640,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { } /** 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 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { 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 1f3454de14d7..405cfd38d49a 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.authentication.domain.interactor.authenticationInter 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 @@ class SceneBackInteractorTest : SysuiTestCase() { ) } + @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 edaa3d373807..bf97afed92f4 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.KeyguardState 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 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { 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 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { .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 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { /** 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 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { 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 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { 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 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { } /** 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 4a7d8b0f8287..7fe3d8d08afa 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 @@ package com.android.systemui.scene.domain.interactor 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.domain.resolver.homeSceneFamilyResolver 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 @@ class SceneInteractorTest : SysuiTestCase() { } @Test - fun transitioningTo() = + fun transitioningTo_sceneChange() = testScope.runTest { val transitionState = MutableStateFlow<ObservableTransitionState>( @@ -293,6 +295,51 @@ class SceneInteractorTest : SysuiTestCase() { } @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 d1804608d130..763a1a943bf8 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.internal.policy.IKeyguardDismissCallback 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.Companion.se 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { // WHEN the device is occluded, kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( true, - mock() + mock(), ) // THEN scenes are not visible assertThat(isVisible).isFalse() @@ -393,6 +392,7 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { @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 @@ class SceneContainerStartableTest : SysuiTestCase() { initialSceneKey = Scenes.Lockscreen, authenticationMethod = AuthenticationMethodModel.Pin, isDeviceUnlocked = false, - startsAwake = false + startsAwake = false, ) assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) underTest.start() @@ -1228,11 +1210,14 @@ class SceneContainerStartableTest : SysuiTestCase() { @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 @@ class SceneContainerStartableTest : SysuiTestCase() { ) .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() - } - - // Changing to the Lockscreen scene shouldn't report a successful unlock. - sceneInteractor.changeScene(Scenes.Lockscreen, "reason") + 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() + } + + // 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 @@ class SceneContainerStartableTest : SysuiTestCase() { ) .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 @@ class SceneContainerStartableTest : SysuiTestCase() { kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( true, - mock() + mock(), ) runCurrent() verify(notificationShadeWindowController, times(1)).setKeyguardOccluded(true) @@ -1623,10 +1623,7 @@ class SceneContainerStartableTest : SysuiTestCase() { @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 @@ class SceneContainerStartableTest : SysuiTestCase() { }, verifyAfterTransition = { verify(centralSurfaces) - .setInteracting( - StatusBarManager.WINDOW_STATUS_BAR, - false, - ) + .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false) }, ) @@ -1661,11 +1655,7 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { }, verifyAfterTransition = { verify(centralSurfaces) - .setInteracting( - StatusBarManager.WINDOW_STATUS_BAR, - false, - ) + .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false) }, ) @@ -1699,11 +1686,7 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 @@ class SceneContainerStartableTest : SysuiTestCase() { runCurrent() verifyDuringTransition?.invoke() - transitionStateFlow.value = - ObservableTransitionState.Idle( - currentScene = toScene, - ) + transitionStateFlow.value = ObservableTransitionState.Idle(currentScene = toScene) runCurrent() verifyAfterTransition?.invoke() } @@ -2262,7 +2232,7 @@ class SceneContainerStartableTest : SysuiTestCase() { private fun TestScope.allowHapticsOnSfps( isPowerButtonDown: Boolean = false, - lastPowerPress: Long = 10000 + lastPowerPress: Long = 10000, ) { kosmos.fakeKeyEventRepository.setPowerButtonDown(isPowerButtonDown) @@ -2287,7 +2257,7 @@ class SceneContainerStartableTest : SysuiTestCase() { 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 851b7b986527..ba559b59c92e 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 @@ package com.android.systemui.shade.domain.interactor 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.data.repository.fakeDeviceEntryFingerprintA 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 @@ class PanelExpansionInteractorImplTest : SysuiTestCase() { @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 @@ class PanelExpansionInteractorImplTest : SysuiTestCase() { 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 2a2817b9af73..ad2b23e49536 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 @@ class ShadeModeInteractorImplTest : SysuiTestCase() { } @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 469a7bc6d9fb..305367213571 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.collection.render.GroupMember 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 6c8db91d49bb..84f7a5133593 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 875b7b6d1f40..000000000000 --- 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 06d1bf4c01cb..a15532f7aed2 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 7d765ce7ac6f..825824aa958a 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 000000000000..c2e945d38a70 --- /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 000000000000..bec6f353f380 --- /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 2a27b47e54ca..3efe7a560d94 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 e1808fa7532d..00846cb10378 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 589d9ddd20b9..f9c2aef5f070 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 @@ Action + ESC for this.</string> <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 @@ Action + ESC for this.</string> <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 0f1da509468a..8f55961af4e9 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -70,7 +70,6 @@ android_library { "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 4db6ab6ea579..f358ba2d3ccd 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.graphics.drawable.Drawable; 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 android.widget.FrameLayout; 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 @@ public class FloatingRotationButton implements RotationButton { 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 @@ public class FloatingRotationButton implements RotationButton { @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 28f1381d94af..b43d8b667756 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -19,10 +19,8 @@ package com.android.keyguard; 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.internal.widget.LockscreenCredential; 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 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey 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 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey 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 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey 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 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey 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 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey } } - 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 92e5432ad243..ff788484c819 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.Flags; 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.user.domain.interactor.SelectedUserInteractor; 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 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> 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 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> 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 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; @@ -255,7 +254,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> mSelectedUserInteractor = selectedUserInteractor; mUiEventLogger = uiEventLogger; mKeyguardKeyboardInteractor = keyguardKeyboardInteractor; - mMSDLPlayer = msdlPlayer; + mBouncerHapticPlayer = bouncerHapticPlayer; mUserActivityNotifier = userActivityNotifier; } @@ -272,7 +271,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> 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 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> 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 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> 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 905fa0939a46..4628ed705d00 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -19,7 +19,6 @@ package com.android.keyguard; 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.internal.widget.LockPatternUtils; 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.statusbar.policy.DevicePostureController; 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 @@ public class KeyguardPasswordViewController 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 f74d93e1d88d..7fb66640b29f 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.LockPatternView.Cell; 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.res.R; 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 @@ public class KeyguardPatternViewController private LockPatternView mLockPatternView; private CountDownTimer mCountdownTimer; private AsyncTask<?, ?, ?> mPendingLockCheck; - private MSDLPlayer mMSDLPlayer; private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() { @Override @@ -80,7 +77,7 @@ public class KeyguardPatternViewController }; private final LockPatternView.ExternalHapticsPlayer mExternalHapticsPlayer = () -> { - BouncerHapticHelper.INSTANCE.playPatternDotFeedback(mMSDLPlayer, mView); + mBouncerHapticPlayer.playPatternDotFeedback(mView); }; /** @@ -174,9 +171,8 @@ public class KeyguardPatternViewController 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 @@ public class KeyguardPatternViewController 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 @@ public class KeyguardPatternViewController 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 @@ public class KeyguardPatternViewController 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 f575cf29f402..d999994a3312 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.internal.widget.LockPatternUtils; 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 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB 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 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB 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 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB 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 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB 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 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB 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 3b5bf1a422a3..d3c02e6f6449 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -18,7 +18,6 @@ package com.android.keyguard; 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.util.LatencyTracker; 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.res.R; 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 @@ public class KeyguardPinViewController 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 47fe2b22b5f6..1c1acf83fa12 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 android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 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.util.LatencyTracker; 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 @@ public class KeyguardSimPinViewController 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 c688acb8d760..9adc5bae1ada 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.util.LatencyTracker; 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 @@ public class KeyguardSimPukViewController 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 4fb80de2d4ec..7fe4ec852045 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 android.widget.TextView; 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 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { 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 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { // 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 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { 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 aa9623127d17..d4e74d3bb906 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 @@ public class AmbientStatusBarView extends ConstraintLayout { 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 class AmbientStatusBarView extends ConstraintLayout { 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 @@ public class AmbientStatusBarView extends ConstraintLayout { 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 @@ public class AmbientStatusBarView extends ConstraintLayout { 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 04595a2a698e..75024c66d558 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.text.format.DateFormat; 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; 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 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus 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 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus private final StatusBarWindowStateListener mStatusBarWindowStateListener = this::onSystemStatusBarStateChanged; + private final PrivacyItemController.Callback mPrivacyItemControllerCallback = + this::onPrivacyItemsChanged; + @Inject public AmbientStatusBarViewController( AmbientStatusBarView view, @@ -147,6 +155,7 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus DreamOverlayStateController dreamOverlayStateController, UserTracker userTracker, WifiInteractor wifiInteractor, + PrivacyItemController privacyItemController, CommunalSceneInteractor communalSceneInteractor, @DreamLog LogBuffer logBuffer) { super(view); @@ -163,6 +172,7 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus mDreamOverlayStateController = dreamOverlayStateController; mUserTracker = userTracker; mWifiInteractor = wifiInteractor; + mPrivacyItemController = privacyItemController; mCommunalSceneInteractor = communalSceneInteractor; mLogger = new DreamLogger(logBuffer, TAG); } @@ -174,10 +184,12 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus // 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 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus 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 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus 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 c28bce2e0de1..6d6cd45eaa58 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 @@ constructor( /** 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 d7a4863bde02..7647cf6081bf 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 @@ object ComposeBouncerFlags { } /** + * 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/BouncerHapticPlayer.kt index 1faacff996ca..19e7537007bf 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt @@ -23,25 +23,28 @@ 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 object to deliver haptic feedback in bouncer interactions. */ -object BouncerHapticHelper { +/** + * 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() } - private val authInteractionProperties = 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. - * @param[player] The [MSDLPlayer] that delivers the correct feedback. */ - fun playMSDLAuthenticationFeedback( - authenticationSucceeded: Boolean, - player: MSDLPlayer?, - ) { - if (player == null || !Flags.msdlFeedback()) { - return - } + fun playAuthenticationFeedback(authenticationSucceeded: Boolean) { + if (!isEnabled) return val token = if (authenticationSucceeded) { @@ -49,7 +52,7 @@ object BouncerHapticHelper { } else { MSDLToken.FAILURE } - player.playToken(token, authInteractionProperties) + msdlPlayer.get().playToken(token, authInteractionProperties) } /** @@ -57,17 +60,29 @@ object BouncerHapticHelper { * 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()) { + fun playPatternDotFeedback(view: View?) { + if (!isEnabled) { view?.performHapticFeedback( HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING, ) } else { - player.playToken(MSDLToken.DRAG_INDICATOR) + 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 d223657aa74d..c60f93244437 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 @@ constructor( 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 @@ constructor( 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 df6ca9bf0511..da29c6230cd8 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.keyguard.PinShapeAdapter 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 @@ constructor( } } + /** 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 dcd419512498..a62600d65d4b 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 @@ import javax.inject.Inject; public class FalsingCollectorFake implements FalsingCollector { public KeyEvent lastKeyEvent = null; + public boolean avoidGestureInvoked = false; @Override public void init() { @@ -87,6 +88,16 @@ public class FalsingCollectorFake implements FalsingCollector { @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 b570e14c646a..a687734ff499 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 @@ constructor( 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 @@ constructor( allOf( communalSettingsInteractor.isCommunalEnabled, not(keyguardInteractor.isEncryptedOrLockdown), - keyguardInteractor.isKeyguardShowing + keyguardInteractor.isKeyguardShowing, ) .distinctUntilChanged() .onEach { available -> @@ -342,7 +342,7 @@ constructor( 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 @@ constructor( } /** 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 @@ constructor( IntentFilter().apply { addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) - }, + } ) .emitOnStart() @@ -450,7 +448,7 @@ constructor( 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 @@ constructor( /** 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 @@ constructor( * 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 @@ constructor( ) // 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 @@ constructor( * 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 @@ constructor( } } + // 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 @@ constructor( * 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 ac496f01a39d..3826fb40ea3d 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.data.repository.CommunalSceneRepository 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.flatMapLatest 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 @@ constructor( @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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( /** 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 @@ constructor( * 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 @@ constructor( } } .distinctUntilChanged() + .onStart { SceneContainerFlag.assertInLegacyMode() } /** * Flow that emits a boolean if the communal UI is fully visible and not in transition. @@ -219,7 +250,10 @@ constructor( 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 @@ constructor( 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 4c821d482eef..c2f6e85a33e4 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 @@ sealed interface CommunalContentModel { /** 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 @@ sealed interface CommunalContentModel { 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 @@ sealed interface CommunalContentModel { 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 @@ sealed interface CommunalContentModel { 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 d5a56c1e9ee0..e562dfcbbc74 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 @@ object CommunalScenes { @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 d69ba1b23aa3..53109ac69fa9 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 @@ constructor( 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 @@ constructor( ongoingContent, communalInteractor.widgetContent, communalInteractor.ctaTileContent, - ) { ongoing, widgets, ctaTile, - -> + ) { ongoing, widgets, ctaTile -> ongoing + widgets + ctaTile } } @@ -172,10 +165,10 @@ constructor( 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 @@ constructor( combine( keyguardTransitionInteractor.isFinishedIn( scene = Scenes.Communal, - stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB + stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB, ), communalInteractor.isIdleOnCommunal, shadeInteractor.isAnyFullyExpanded, @@ -221,7 +214,7 @@ constructor( 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 @@ constructor( AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id, resources .getString(R.string.accessibility_action_label_edit_widgets) - .lowercase() + .lowercase(), ) ) } @@ -238,7 +231,7 @@ constructor( override fun performAccessibilityAction( host: View, action: Int, - args: Bundle? + args: Bundle?, ): Boolean { when (action) { AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id -> { @@ -271,9 +264,7 @@ constructor( } } - 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 0e39a99765bd..ec0322736f4b 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.os.Bundle 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 @@ class WidgetViewFactory 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 @@ constructor( 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 000000000000..f3416216afdd --- /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 10a565f49a8f..b46698ed87f2 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 @@ class CommunalAppWidgetHost( 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 @@ class CommunalAppWidgetHost( @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 684303ae73cc..f4962085000c 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 @@ package com.android.systemui.communal.widgets 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 @@ interface CommunalWidgetModule { 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 d84dc209196e..13b4aa9b55cb 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.keyguard.shared.model.KeyguardState 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 @@ constructor( 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 7018f9dc8556..dbd7f0739f6c 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.SysUISingleton 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.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.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @@ -59,6 +63,7 @@ constructor( private val deviceUnlockedInteractor: DeviceUnlockedInteractor, private val alternateBouncerInteractor: AlternateBouncerInteractor, private val dismissCallbackRegistry: DismissCallbackRegistry, + sceneBackInteractor: SceneBackInteractor, ) { /** * Whether the device is unlocked. @@ -86,19 +91,40 @@ constructor( * 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 @@ constructor( }, isLockscreenEnabled, deviceUnlockedInteractor.deviceUnlockStatus, - isDeviceEntered + isDeviceEntered, ) { isNoneAuthMethod, isLockscreenEnabled, deviceUnlockStatus, isDeviceEntered -> val isSwipeAuthMethod = isNoneAuthMethod && isLockscreenEnabled (isSwipeAuthMethod || @@ -155,9 +181,7 @@ constructor( * 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 1f5878b4698f..a327e4a76c49 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.util.Log 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.map 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( */ 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 @@ constructor( // 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 @@ constructor( TAG, "combining enabled=$enabledDisplaysIds, " + "connectedExternalDisplayIds=$connectedExternalDisplayIds, " + - "ignored=$ignoredDisplayIds" + "ignored=$ignoredDisplayIds", ) } connectedExternalDisplayIds - enabledDisplaysIds - ignoredDisplayIds @@ -382,7 +362,7 @@ constructor( 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 dcca12f29287..11a0543d97d1 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 @@ fun ShortcutHelper( useSinglePane, onSearchQueryChanged, modifier, - onKeyboardSettingsClicked + onKeyboardSettingsClicked, ) } else -> { @@ -159,7 +159,7 @@ private fun ActiveShortcutHelper( useSinglePane: @Composable () -> Boolean, onSearchQueryChanged: (String) -> Unit, modifier: Modifier, - onKeyboardSettingsClicked: () -> Unit + onKeyboardSettingsClicked: () -> Unit, ) { var selectedCategoryType by remember(shortcutsUiState.defaultSelectedCategory) { @@ -183,7 +183,7 @@ private fun ActiveShortcutHelper( shortcutsUiState.shortcutCategories, selectedCategoryType, onCategorySelected = { selectedCategoryType = it }, - onKeyboardSettingsClicked + onKeyboardSettingsClicked, ) } } @@ -223,14 +223,14 @@ private fun ShortcutHelperSinglePane( 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 @@ private fun CategoryItemSinglePane( 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 @@ fun ShortcutCategoryIcon( 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 ShortcutCategory.label(context: Context): String = private fun getApplicationLabelForCurrentApp( type: ShortcutCategoryType.CurrentApp, - context: Context + context: Context, ): String { val packageManagerForUser = CentralSurfaces.getPackageManagerForUser(context, context.userId) return try { @@ -358,7 +354,7 @@ private fun getApplicationLabelForCurrentApp( packageManagerForUser.getApplicationInfoAsUser( type.packageName, /* flags = */ 0, - context.userId + context.userId, ) packageManagerForUser.getApplicationLabel(currentAppInfo).toString() } catch (e: NameNotFoundException) { @@ -377,13 +373,13 @@ private fun RotatingExpandCollapseIcon(isExpanded: Boolean) { } 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 @@ private fun RotatingExpandCollapseIcon(isExpanded: Boolean) { } else { stringResource(R.string.shortcut_helper_content_description_expand_icon) }, - tint = MaterialTheme.colorScheme.onSurface + tint = MaterialTheme.colorScheme.onSurface, ) } @@ -435,11 +431,11 @@ private fun ShortcutHelperTwoPane( 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 @@ private fun NoSearchResultsText(horizontalPadding: Dp, fillHeight: Boolean) { 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 @@ private fun SubCategoryContainerDualPane(searchQuery: String, subCategory: Short 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 @@ private fun ShortcutView(modifier: Modifier, searchQuery: String, shortcut: Shor isFocused = isFocused, focusColor = MaterialTheme.colorScheme.secondary, padding = 8.dp, - cornerRadius = 16.dp + cornerRadius = 16.dp, ) ) { Row( @@ -528,21 +524,12 @@ private fun ShortcutView(modifier: Modifier, searchQuery: String, shortcut: Shor 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 @@ fun ShortcutIcon( @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 @@ private fun ShortcutKeyContainer(shortcutKeyContent: @Composable BoxScope.() -> Modifier.height(36.dp) .background( color = MaterialTheme.colorScheme.surfaceContainer, - shape = RoundedCornerShape(12.dp) - ), + shape = RoundedCornerShape(12.dp), + ) ) { shortcutKeyContent() } @@ -630,7 +614,7 @@ private fun BoxScope.ShortcutIconKey(key: ShortcutKey.Icon) { 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 @@ private fun StartSidePanel( KeyboardSettings( horizontalPadding = 24.dp, verticalPadding = 24.dp, - onKeyboardSettingsClicked + onKeyboardSettingsClicked, ) } } @@ -710,7 +694,7 @@ private fun StartSidePanel( private fun CategoriesPanelTwoPane( categories: List<ShortcutCategory>, selectedCategory: ShortcutCategoryType?, - onCategoryClicked: (ShortcutCategory) -> Unit + onCategoryClicked: (ShortcutCategory) -> Unit, ) { Column { categories.fastForEach { @@ -718,7 +702,7 @@ private fun CategoriesPanelTwoPane( label = it.label(LocalContext.current), iconSource = it.icon, selected = selectedCategory == it.type, - onClick = { onCategoryClicked(it) } + onClick = { onCategoryClicked(it) }, ) } } @@ -736,29 +720,29 @@ private fun CategoryItemTwoPane( 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 @@ private fun CategoryItemTwoPane( fontSize = 18.sp, color = colors.textColor(selected).value, style = MaterialTheme.typography.headlineSmall, - text = label + text = label, ) } } @@ -777,7 +761,7 @@ private fun Modifier.outlineFocusModifier( isFocused: Boolean, focusColor: Color, padding: Dp, - cornerRadius: Dp + cornerRadius: Dp, ): Modifier { if (isFocused) { return this.drawWithContent { @@ -795,7 +779,7 @@ private fun Modifier.outlineFocusModifier( 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 @@ private fun TitleBar() { Text( text = stringResource(R.string.shortcut_helper_title), color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.headlineSmall + style = MaterialTheme.typography.headlineSmall, ) - } + }, ) } @@ -852,7 +836,7 @@ private fun ShortcutsSearchBar(onQueryChange: (String) -> Unit) { 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 ShortcutsSearchBar(onQueryChange: (String) -> Unit) { 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 @@ private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick 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 @@ object ShortcutHelper { 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 000000000000..3ba3bd8fdc2f --- /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 20397431659b..799999aff29b 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.composable.ShortcutHelper 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 @@ import kotlinx.coroutines.launch */ 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 @@ constructor( setupEdgeToEdge() super.onCreate(savedInstanceState) setContentView(R.layout.activity_keyboard_shortcut_helper) - setUpBottomSheetWidth() + setUpWidth() expandBottomSheet() setUpInsets() setUpPredictiveBack() @@ -80,6 +79,13 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( } 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 228e01edc99b..cd5daf9a99f0 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 @@ constructor( .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 @@ constructor( .collect { startTransitionTo( KeyguardState.PRIMARY_BOUNCER, - ownerReason = "#listenForLockscreenToPrimaryBouncer" + ownerReason = "#listenForLockscreenToPrimaryBouncer", ) } } @@ -238,7 +238,7 @@ constructor( getDefaultAnimatorForTransitionsToState( KeyguardState.LOCKSCREEN ) - .apply { duration = 0 } + .apply { duration = 0 }, ) ) } @@ -249,6 +249,8 @@ constructor( 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 @@ constructor( 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 60c53863535d..eb9b07add12d 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.domain.interactor.AlternateBouncerInteractor 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.GONE 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( merge( finishedTransitionToGone, isOnShadeWhileUnlocked.filter { it }.map {}, - dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction + dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction, ) .sample(dismissAction) .filterNot { it is DismissAction.None } @@ -142,11 +138,11 @@ constructor( 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 @@ constructor( } fun runAfterKeyguardGone(runnable: Runnable) { - if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return + if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return setDismissAction( DismissAction.RunAfterKeyguardGone( dismissAction = { runnable.run() }, @@ -176,18 +172,18 @@ constructor( } 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 44aafabb103a..ad1a32e70a5b 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 @@ constructor( .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 @@ constructor( */ 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 420fbd4ae48d..7fd348b8b40e 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.DeadObjectException 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.KeyguardWmStateRefactor 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 @@ constructor( @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 @@ constructor( 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 @@ constructor( } } } + + 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) + } + + /** 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 } -}
\ No newline at end of file +} 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 e19b72e26567..c4f231dfc012 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 @@ constructor( MutableSharedFlow<Float>( replay = 1, extraBufferCapacity = 2, - onBufferOverflow = BufferOverflow.DROP_OLDEST + onBufferOverflow = BufferOverflow.DROP_OLDEST, ) .also { it.tryEmit(0f) } } @@ -97,8 +97,8 @@ constructor( SharingStarted.Eagerly, WithPrev( sceneInteractor.transitionState.value, - sceneInteractor.transitionState.value - ) + sceneInteractor.transitionState.value, + ), ) /** @@ -156,7 +156,7 @@ constructor( 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 @@ constructor( transitionMap.getOrPut(mappedEdge) { MutableSharedFlow( extraBufferCapacity = 10, - onBufferOverflow = BufferOverflow.DROP_OLDEST + onBufferOverflow = BufferOverflow.DROP_OLDEST, ) } @@ -262,7 +262,7 @@ constructor( 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 @@ constructor( * 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 @@ constructor( .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 @@ constructor( 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 7e13d2282e05..4b62eab08775 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 @@ constructor( } .stateIn( scope = applicationScope, - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.Eagerly, initialValue = KeyguardQuickAffordanceViewModel( slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId() @@ -202,7 +202,7 @@ constructor( } .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 eaa61a113ee6..38ca888eee38 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.AOD 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 @@ constructor( 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 ecae0797dbc6..3b266f945aab 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 @@ package com.android.systemui.keyguard.ui.viewmodel 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 @@ constructor( addAll( when (shadeMode) { - ShadeMode.Single -> fullscreenShadeActions() - ShadeMode.Split -> - fullscreenShadeActions(transitionKey = ToSplitShade) + ShadeMode.Single -> singleShadeActions() + ShadeMode.Split -> splitShadeActions() ShadeMode.Dual -> dualShadeActions() } ) @@ -84,18 +81,26 @@ constructor( .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 bf9ef8c5d24e..8505a784d302 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 @@ constructor( 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 4251b81226b3..d59658947771 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.TextPaint; 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 @@ public class MediaProjectionPermissionActivity extends Activity { 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 @@ public class MediaProjectionPermissionActivity extends Activity { 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 db5a545c3f71..0d748a1cf077 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( ) } - 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 89d76f0038ee..f7a505a413d1 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 class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 b6868c172a9f..63bfbd1dc1ba 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 @@ package com.android.systemui.notifications.ui.viewmodel 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 @@ class NotificationsShadeOverlayActionsViewModel @AssistedInject constructor() : 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 4018320f2195..ca7b06a16a72 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.Context; 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 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } @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 61c4c8c0de86..31519a95d621 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 @@ package com.android.systemui.qs.ui.viewmodel 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 a402a9d5ae7c..ac49e91c777c 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.navigationbar.views.buttons.KeyButtonView; 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 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis 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 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } 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 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis 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 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, Provider<SceneInteractor> sceneInteractor, + Provider<ShadeInteractor> shadeInteractor, UserTracker userTracker, UserManager userManager, WakefulnessLifecycle wakefulnessLifecycle, @@ -688,6 +684,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis 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 1aa982fd32f3..e441a23d3725 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.notifications.ui.composable.NotificationsShadeSessio 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 @@ import dagger.multibindings.IntoMap EmptySceneModule::class, GoneSceneModule::class, NotificationsShadeOverlayModule::class, - NotificationsShadeSceneModule::class, NotificationsShadeSessionModule::class, QuickSettingsShadeOverlayModule::class, QuickSettingsSceneModule::class, @@ -56,8 +53,6 @@ import dagger.multibindings.IntoMap // 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 7f0cf86bee02..a89f752fe212 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.notifications.ui.composable.NotificationsShadeSessio 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 @@ import dagger.multibindings.IntoMap 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 2d40845df802..afb72f03b28d 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 @@ constructor( 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 429b47bcfba1..667827ac4724 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 @@ constructor( 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 0d24adc30799..f20e5a54f6ed 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 @@ constructor( ) /** - * 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 @@ constructor( .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 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = isVisibleInternal() + initialValue = isVisibleInternal(), ) /** Whether there's an ongoing remotely-initiated user interaction. */ @@ -259,10 +255,7 @@ constructor( * 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( * @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 a3132736fe33..000000000000 --- 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 923e712af15d..000000000000 --- 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 18767f576fef..e11ffccb0be3 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.deviceentry.shared.model.DeviceUnlockSource 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.plugins.FalsingManager.FalsingBeliefListener 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 @@ import kotlinx.coroutines.launch * 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( } 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 @@ constructor( " 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 @@ constructor( 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 115d664c4ccd..82b4b1c57f7e 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 @@ object Scenes { @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 @@ object Scenes { * 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 @@ object Scenes { * 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 @@ object SceneFamilies { * 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 c451704aa0f8..af1f5a716961 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 @@ constructor( 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 @@ constructor( ) } } + // 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 d4e711e38b3c..663ba20070bd 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.concurrent.futures.CallbackToFutureAdapter; 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 @@ public class ImageExporter { 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 @@ public class ImageExporter { 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 @@ public class ImageExporter { bitmap, ZonedDateTime.now(ZoneId.systemDefault()), format, - mQuality, /* publish */ true, owner, mFlags, + mQuality, + owner, createSystemFileDisplayName(fileName, format), true /* allowOverwrite */)); } @@ -199,8 +196,7 @@ public class ImageExporter { 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 @@ public class ImageExporter { 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 class ImageExporter { public String fileName; public long timestamp; public CompressFormat format; - public boolean published; @Override public String toString() { @@ -259,7 +253,6 @@ public class ImageExporter { 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 @@ public class ImageExporter { 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 @@ public class ImageExporter { 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 @@ public class ImageExporter { mQuality = quality; mOwner = owner; mFileName = fileName; - mPublish = publish; - mFlags = flags; mAllowOverwrite = allowOverwrite; } @@ -320,7 +308,7 @@ public class ImageExporter { start = Instant.now(); } - uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner, mFlags, + uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner, mAllowOverwrite); throwIfInterrupted(); @@ -332,10 +320,7 @@ public class ImageExporter { 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 @@ public class ImageExporter { } 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 31813b240c37..42499f043457 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.BounceInterpolator; 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 813df1127fb8..859926cab6a9 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 @@ public interface ShadeController extends CoreStartable { /** */ 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 07836e44e83d..b7a95e989317 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 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { 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 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { private boolean mExpandedVisible; private boolean mLockscreenOrShadeVisible; - private NotificationShadeWindowViewController mNotificationShadeWindowViewController; private ShadeVisibilityListener mShadeVisibilityListener; @Inject @@ -87,6 +87,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { DeviceProvisionedController deviceProvisionedController, NotificationShadeWindowController notificationShadeWindowController, @DisplayId int displayId, + Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewController, Lazy<NotificationPanelViewController> shadeViewControllerLazy, Lazy<AssistManager> assistManagerLazy, Lazy<NotificationGutsManager> gutsManager @@ -105,6 +106,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { mDeviceProvisionedController = deviceProvisionedController; mGutsManager = gutsManager; mNotificationShadeWindowController = notificationShadeWindowController; + mNotifShadeWindowViewController = notificationShadeWindowViewController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mDisplayId = displayId; mKeyguardStateController = keyguardStateController; @@ -139,7 +141,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { // 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 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { @Override public void cancelExpansionAndCollapseShade() { if (getNpvc().isTracking()) { - mNotificationShadeWindowViewController.cancelCurrentTouch(); + mNotifShadeWindowViewController.get().cancelCurrentTouch(); } if (getNpvc().isPanelExpanded() && mStatusBarStateController.getState() == StatusBarState.SHADE) { @@ -367,14 +369,8 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { 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 5d03a28e7f09..361226a4df18 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 @@ constructor( } 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 @@ constructor( if (shadeInteractor.isAnyExpanded.value) { commandQueue.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, - true /* force */ + true, /* force */ ) assistManagerLazy.get().hideAssist() } @@ -172,17 +169,11 @@ constructor( } 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 c49cfbde25a5..cb589aa10cd9 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 @@ constructor( if (qsVisible && field != value) { header.alpha = ShadeInterpolation.getContentAlpha(value) field = value + updateIgnoredSlots() } } @@ -538,7 +539,7 @@ constructor( 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 e276f8807df7..cea521f094be 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( // 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 @@ constructor( } else -> flowOf(1f) } - is ObservableTransitionState.Transition.ShowOrHideOverlay, - is ObservableTransitionState.Transition.ReplaceOverlay -> - TODO("b/359173565: Handle overlay transitions") } } @@ -132,7 +132,13 @@ constructor( 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 6fb96da2c186..b046c50b05d3 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 @@ interface BaseShadeInteractor { * 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 6c0b55a5dd57..fb1482890b87 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 @@ class ShadeInteractorEmptyImpl @Inject constructor() : ShadeInteractor { 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 f48e31e1d7eb..df094864a71b 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 @@ constructor( keyguardRepository.statusBarState, repository.legacyShadeExpansion, repository.qsExpansion, - sharedNotificationContainerInteractor.isSplitShadeEnabled + sharedNotificationContainerInteractor.isSplitShadeEnabled, ) { lockscreenShadeExpansion, statusBarState, @@ -97,13 +97,13 @@ constructor( 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 @@ constructor( 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 @@ constructor( */ 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 e84cfa51dd67..81bf712f21e5 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 @@ constructor( .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 @@ constructor( 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 @@ constructor( } } .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 e525b86a2f9e..0fb379017be9 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.Background 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 77ae679bf018..caa45137ed98 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 @@ interface ShadeModeInteractor { */ 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 index 0e7beb9d17da..02a29e29035d 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.HeadsUpReposi 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 index 9f76429bd6a5..021d30144b32 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 index 26bd7ac74d97..0927a728783f 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 2b0d2aa6ea2a..63c9e8be9ead 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 637cadde6fc6..920541d101cf 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 @@ object FooterViewBinder { viewModel, clearAllNotifications, launchNotificationSettings, - launchNotificationHistory + launchNotificationHistory, ) } } @@ -55,21 +55,15 @@ object FooterViewBinder { 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 @@ object FooterViewBinder { viewModel: FooterViewModel, clearAllNotifications: View.OnClickListener, ) = coroutineScope { - footer.setClearAllButtonClickListener(clearAllNotifications) - launch { viewModel.clearAllButton.labelId.collect { textId -> footer.setClearAllButtonText(textId) @@ -96,18 +88,21 @@ object FooterViewBinder { 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 @@ object FooterViewBinder { 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 1214440a6b65..7543f3b48e48 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.ShadeScrim 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 bcdc3bc583ad..e5f63c1cb480 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.row.NotificationSnooze; 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 3e42413932f4..8d7007b2fba4 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.keyguard.domain.interactor.KeyguardInteractor 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.StateFlow 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 @@ constructor( ): 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 @@ constructor( (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 @@ constructor( 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 -> + expandFractionDuringOverlayTransition( + transition = transitionState, + currentScene = transitionState.currentScene, + shadeExpansion = shadeExpansion, + ) + is Transition.ReplaceOverlay -> + expandFractionDuringOverlayTransition( + transition = transitionState, + currentScene = transitionState.currentScene, + shadeExpansion = shadeExpansion, ) - is Transition.ShowOrHideOverlay, - is Transition.ReplaceOverlay -> TODO("b/359173565: Handle overlay transitions") } } .distinctUntilChanged() @@ -166,14 +199,14 @@ constructor( 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 @@ constructor( /** 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 @@ constructor( } } + 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 d4ef42c687e5..5b37468c9da6 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 @@ constructor( 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 7227b9380b61..50e92498b114 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { 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 0d0f2cd50a29..7919c84152b2 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 45aee5b8c22f..a6581159d33e 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.ViewTreeObserver.OnComputeInternalInsetsListener; 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 @@ public final class StatusBarTouchableRegionManager implements Dumpable { 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 @@ public final class StatusBarTouchableRegionManager implements Dumpable { if (SceneContainerFlag.isEnabled()) { javaAdapter.alwaysCollectFlow( sceneInteractor.get().getTransitionState(), - this::onSceneChanged); + this::onSceneContainerTransition); javaAdapter.alwaysCollectFlow( sceneInteractor.get().isRemoteUserInteractionOngoing(), this::onRemoteUserInteractionOngoingChanged); @@ -172,11 +175,13 @@ public final class StatusBarTouchableRegionManager implements Dumpable { } } - 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 @@ public final class StatusBarTouchableRegionManager implements Dumpable { // 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 ca9436315dcc..c089092c9b86 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 androidx.annotation.WorkerThread; 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 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa 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 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa @Main Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager, @Nullable BluetoothAdapter bluetoothAdapter) { - mContext = context; mDumpManager = dumpManager; mLogger = logger; mBluetoothRepository = bluetoothRepository; @@ -265,21 +262,9 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa } 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 a3b186744537..411ff8b2b542 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.TutorialScreenCon 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 @@ fun BackGestureTutorialScreen( ) ) 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 57d7c84af4ba..0ecbf70f85c3 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.TouchpadGestureHandler 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 @@ fun GestureTutorialScreen( ) { 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 d4eb0cd7327b..f2fec5f5d9b1 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.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.HomeGestureMonitor -import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor @Composable fun HomeGestureTutorialScreen( @@ -49,14 +47,11 @@ fun HomeGestureTutorialScreen( ) ) 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 000000000000..b2fb6cdfcee5 --- /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 65b452a81da8..5a77c04924dd 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 @@ import com.android.systemui.res.R fun TutorialSelectionScreen( onBackTutorialClicked: () -> Unit, onHomeTutorialClicked: () -> Unit, - onActionKeyTutorialClicked: () -> Unit, + onRecentAppsTutorialClicked: () -> Unit, onDoneButtonClicked: () -> Unit, ) { Column( @@ -55,7 +55,7 @@ fun TutorialSelectionScreen( TutorialSelectionButtons( onBackTutorialClicked = onBackTutorialClicked, onHomeTutorialClicked = onHomeTutorialClicked, - onActionKeyTutorialClicked = onActionKeyTutorialClicked, + onRecentAppsTutorialClicked = onRecentAppsTutorialClicked, modifier = Modifier.padding(60.dp) ) DoneButton( @@ -69,7 +69,7 @@ fun TutorialSelectionScreen( private fun TutorialSelectionButtons( onBackTutorialClicked: () -> Unit, onHomeTutorialClicked: () -> Unit, - onActionKeyTutorialClicked: () -> Unit, + onRecentAppsTutorialClicked: () -> Unit, modifier: Modifier = Modifier ) { Row( @@ -90,8 +90,8 @@ private fun TutorialSelectionButtons( 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 821b51a18a8e..46ea352ff85a 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.InputDeviceTutorialLogger.Tutor 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 @@ fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> U 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 @@ fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> U 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 43266ad8da76..599e1b1eff75 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 @@ enum class Screen { 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 030a20ab8c56..079c72f049a6 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 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa != 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 7786453814e0..db4f9ef13bd6 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 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, : 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 c0d8be322cd6..4bb01ec1e1df 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.KeyguardAbsKeyInputView.KeyDownListener; 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 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { 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 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { 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 873bc2c92431..2c1dacdfae73 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.FalsingCollector 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 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback> + private val kosmos = testKosmos() + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -151,8 +155,8 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { 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 f141a4926149..9cd52153eff6 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.Flags 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 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { private val updateMonitorCallbackArgumentCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + private val kosmos = testKosmos() + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -103,8 +107,8 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { fakeFeatureFlags, mSelectedUserInteractor, keyguardKeyboardInteractor, - null, - mUserActivityNotifier + kosmos.bouncerHapticPlayer, + mUserActivityNotifier, ) underTest.init() underTest.onViewAttached() @@ -162,14 +166,14 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { 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 a03c8391fa0f..3c229975eef5 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.Flags 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 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() { KeyguardMessageAreaController<BouncerKeyguardMessageArea> @Mock private lateinit var mUserActivityNotifier: UserActivityNotifier + private val kosmos = testKosmos() + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -98,8 +102,8 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() { 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 c451c32c4587..400b3b388c31 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 @@ public class MenuViewLayerTest extends SysuiTestCase { 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 76539d776d3d..633efd8bfffd 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 @@ class DisplayRepositoryTest : SysuiTestCase() { 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 @@ class DisplayRepositoryTest : SysuiTestCase() { .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 @@ class DisplayRepositoryTest : SysuiTestCase() { 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 b02cccc2bb8d..4959224ead2d 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 @@ class OverviewProxyServiceTest : SysuiTestCase() { 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 @@ class OverviewProxyServiceTest : SysuiTestCase() { statusBarWinController, sysUiState, mock(), + mock(), userTracker, userManager, wakefulnessLifecycle, @@ -294,7 +293,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { 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 f4d7a5bb3ba9..d58b68b5db6c 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.exifinterface.media.ExifInterface; 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 @@ public class ImageExporterTest extends SysuiTestCase { 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 @@ public class ImageExporterTest extends SysuiTestCase { @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 @@ public class ImageExporterTest extends SysuiTestCase { // 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 @@ public class ImageExporterTest extends SysuiTestCase { @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 886b32b09225..717f82d02c49 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.truth.Truth.assertThat; 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 com.google.common.util.concurrent.Futures; 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { } @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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { } @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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { } @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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { } @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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { } @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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { @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 final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { @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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { }).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 @@ public final class AppClipsViewModelTest extends SysuiTestCase { 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 e0c4ab737511..4bd0c757543b 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.CentralSurfaces; 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 02172383485d..905301eb38ae 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 @@ class ShadeControllerImplTest : SysuiTestCase() { 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 0846ced1826c..fc2ad60cfa72 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 @@ class ShadeHeaderControllerTest : SysuiTestCase() { } @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 b65a90200837..a1750cdd0c84 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.data.repository.fakeKeyguardRepository 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN shade expansion is zero - Truth.assertThat(actual).isEqualTo(.7f) + assertThat(actual).isEqualTo(.7f) } @Test @@ -134,7 +143,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is not fullscreen - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -152,7 +161,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is not fullscreen - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -171,7 +180,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is not fullscreen - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -189,7 +198,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is fullscreen - Truth.assertThat(actual).isTrue() + assertThat(actual).isTrue() } @Test @@ -206,7 +215,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 1 - Truth.assertThat(expansionAmount).isEqualTo(1f) + assertThat(expansionAmount).isEqualTo(1f) } @Test @@ -224,7 +233,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) } @Test @@ -251,19 +260,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN qs is bypassing shade - Truth.assertThat(actual).isTrue() + assertThat(actual).isTrue() } fun isQsBypassingShade_shadeToQs() = @@ -350,7 +359,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN qs is not bypassing shade - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -376,19 +385,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() } @Test @@ -432,19 +441,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { // 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 b4f4138fd409..76bb8de71bdd 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.NotificationInte 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 3df4a677b9e5..30556bef6af4 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.NotificationStackScroll 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 c7c08a9d91e7..af043093b6f7 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 @@ public class CentralSurfacesImplTest extends SysuiTestCase { 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 93071bd9305a..2588f1f4fe3f 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.assertFalse; 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 static org.mockito.Mockito.when; 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 com.android.systemui.util.time.FakeSystemClock; 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 @@ public class BluetoothControllerImplTest extends SysuiTestCase { 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 @@ public class BluetoothControllerImplTest extends SysuiTestCase { 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 class BluetoothControllerImplTest extends SysuiTestCase { 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 @@ public class BluetoothControllerImplTest extends SysuiTestCase { } @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 @@ public class BluetoothControllerImplTest extends SysuiTestCase { 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 @@ public class BluetoothControllerImplTest extends SysuiTestCase { 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 cafebb9fd79e..d059c14785a5 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 @@ class RecentAppsGestureMonitorTest : SysuiTestCase() { 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 f5bcc21056e8..feee0a3ed08e 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.Captor 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 @@ class RotationChangeProviderTest : SysuiTestCase() { } @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 index fe6c7417032f..fe6c7417032f 100644 --- 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 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 d31491d22435..25c4bbb75aec 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 @@ package com.android.systemui.classifier 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 2ab82214e497..209d1636e380 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.data.repository.communalSceneRepository 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 @@ val Kosmos.communalSceneInteractor: CommunalSceneInteractor by 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 13116e7fd46f..096022ce1507 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.deviceentry.data.repository.deviceEntryRepository 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 @@ val Kosmos.deviceEntryInteractor by deviceUnlockedInteractor = deviceUnlockedInteractor, alternateBouncerInteractor = alternateBouncerInteractor, dismissCallbackRegistry = dismissCallbackRegistry, + sceneBackInteractor = sceneBackInteractor, ) } diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt index c58df35fd6cb..94982edcd5f3 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt @@ -14,16 +14,15 @@ * limitations under the License. */ -package com.android.systemui.scene +package com.android.systemui.haptics.msdl -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 +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer +import com.android.systemui.kosmos.Kosmos +import com.google.android.msdl.domain.MSDLPlayer +import dagger.Lazy -@Module -interface NotificationsShadeSceneModule { - - @Binds @IntoSet fun notificationsShade(scene: NotificationsShadeScene): Scene -} +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 d920c4f05b03..574bbcd6106c 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 @@ val Kosmos.keyguardDismissActionInteractor by 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 c60305e85b22..f97f30383398 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.deviceEntryInteractor 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 @@ class KosmosJavaAdapter() { 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 8fc40e492bdc..6ced8c3a5cd8 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 @@ package com.android.systemui.qs.ui.viewmodel 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 d17b5750b937..8b124258909a 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.keyguard.domain.interactor.keyguardEnabledInteractor 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 @@ val Kosmos.homeSceneFamilyResolver by 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 9a5698cfb8ca..4228c3c0b110 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.haptics.vibratorHelper 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 @@ val Kosmos.sceneContainerStartable by Fixture { 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 0bc4d54b41c8..ddcc6d60f993 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 @@ val Kosmos.shadeControllerImpl by 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 04d930c72792..92075ea75c4a 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 @@ val Kosmos.shadeInteractorSceneContainerImpl by 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 index 27cd4b6b9885..27cd4b6b9885 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/TestUtils.kt +++ b/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 0458f535c1eb..b1e6fe246f2c 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 @@ constructor( 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 136738fcb343..acb74d30689c 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 @@ public class CameraExtensionsProxyService extends Service { } 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 @@ public class CameraExtensionsProxyService extends Service { 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 3c65f378f33d..d1a3bf9b529f 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -5,6 +5,10 @@ package { // 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 @@ java_library { 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 f7b13d19dbb3..8722ad92ff49 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 7f9d9c29484c..f9b5d2c62828 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 68472c12a568..7a6f9e3669bb 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 @@ public class RavenwoodAwareTestRunnerHook { 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 @@ public class RavenwoodAwareTestRunnerHook { Log.v(TAG, "onAfterInnerRunnerFinished: description=" + description); RavenwoodTestStats.getInstance().onClassFinished(description); - RavenwoodRunnerState.forRunner(runner).exitTestClass(); + runner.mState.exitTestClass(); } /** @@ -133,10 +133,10 @@ public class RavenwoodAwareTestRunnerHook { 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 @@ public class RavenwoodAwareTestRunnerHook { 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 @@ public class RavenwoodAwareTestRunnerHook { 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 @@ public class RavenwoodAwareTestRunnerHook { 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 000000000000..3535cb2b1b79 --- /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 48bed7942cdf..239c8061b757 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 @@ public class RavenwoodContext extends RavenwoodBaseContext { private final File mCacheDir; private final Supplier<Resources> mResourcesSupplier; + private RavenwoodContext mAppContext; + @GuardedBy("mLock") private Resources mResources; @@ -77,8 +79,8 @@ public class RavenwoodContext extends RavenwoodBaseContext { 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 @@ public class RavenwoodContext extends RavenwoodBaseContext { @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 @@ public class RavenwoodContext extends RavenwoodBaseContext { 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 d73afd4c391b..04b67c45ad8e 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 com.android.ravenwood.common.RavenwoodCommonUtils.ensureIsPublicMe 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.lang.reflect.Field; 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 @@ public final class RavenwoodRunnerState { 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 03c9001366e9..f4756c5c58b3 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.HandlerThread; 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 @@ public class RavenwoodRuntimeEnvironmentController { 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]; - - 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); + final boolean isSelfInstrumenting = + Objects.equals(config.mTestPackageName, config.mTargetPackageName); - 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 @@ public class RavenwoodRuntimeEnvironmentController { 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 @@ public class RavenwoodRuntimeEnvironmentController { 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 f3a93c1dacad..d4090e26223a 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 @@ public class RavenwoodSystemServer { 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 bc944d76018d..cb8af0c01a1c 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 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable 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 04e0bedc8aab..ea33aa690173 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 @@ public final class RavenwoodConfig { int mUid = NOBODY_UID; int mPid = sNextPid.getAndIncrement(); - String mPackageName; + String mTestPackageName; + String mTargetPackageName; + + int mMinSdkLevel; boolean mProvideMainThread = false; @@ -71,9 +74,15 @@ public final class RavenwoodConfig { 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 @@ public final class RavenwoodConfig { 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 @@ public final class RavenwoodConfig { } /** - * 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 final class RavenwoodConfig { } 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 7847e7cb5463..984106b21e9a 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 @@ public final class RavenwoodRule implements TestRule { */ @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 index 48ec198a790a..43a28ba72ec9 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/FromLockscreenToNotificationsShadeTransition.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java index 02664c1cc91e..83cbc5265d8f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.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.lockscreenToNotificationsShadeTransition( - durationScale: Double = 1.0, -) { - toNotificationsShadeTransition(durationScale = 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 000000000000..38d1b299b002 --- /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 000000000000..a5a1f17f5ec0 --- /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 000000000000..3dc4c566220c --- /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 000000000000..9491c5315e2a --- /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 000000000000..3079c0612c3c --- /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 000000000000..73ef650a9780 --- /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 000000000000..7528a6270ae1 --- /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 000000000000..0715f5d62654 --- /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 000000000000..395bc2ae37e2 --- /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/FromLockscreenToQuickSettingsShadeTransition.kt b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java index 19aa3a7197d2..15e50ecd4e4a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt +++ b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java @@ -13,14 +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.Edge -import com.android.compose.animation.scene.TransitionBuilder - -fun TransitionBuilder.lockscreenToQuickSettingsShadeTransition( - durationScale: Double = 1.0, -) { - toQuickSettingsShadeTransition(Edge.Top, 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 000000000000..9f3ca6ffcd26 --- /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 000000000000..fdff22210c16 --- /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 a38512ec9f2d..f7f9a8563656 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 @@ class Ravenizer(val options: RavenizerOptions) { } } - 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 e8341e5ceb06..10fe0a3b5a93 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.ArgumentsException 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 @@ class RavenizerOptions( 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 bd9d96d81604..cf6d6f6bcae3 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 @@ class RunnerRewritingAdapter private constructor( 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 @@ class RunnerRewritingAdapter private constructor( // 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 b97ff6217403..9fd2f3178567 100644 --- a/services/accessibility/Android.bp +++ b/services/accessibility/Android.bp @@ -20,11 +20,6 @@ java_library_static { 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 1b2447e2c58a..617cca9d3075 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 @@ import java.util.StringJoiner; * * 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 e10e87c51d59..c9ec16edc54e 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 @@ import java.util.List; /** * 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 000000000000..c3b7087a44c3 --- /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 f04bd9f8ccc0..269419f70b2f 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.Binder; 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 class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { 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 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { 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 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { 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 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { /* 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/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java index 5bb6ae46bae2..c23470a68c70 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt +++ b/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java @@ -14,16 +14,24 @@ * limitations under the License. */ -package com.android.systemui.scene +package com.android.server.appfunctions; -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 +import android.app.appsearch.AppSearchResult; -@Module -interface QuickSettingsShadeSceneModule { +/** Exception to wrap failure result codes returned by AppSearch. */ +public class AppSearchException extends RuntimeException { + private final int resultCode; - @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene + 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 ca43dfaf87ac..e7a861e0a0dc 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.annotation.NonNull; 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 @@ public interface CallerValidator { * * @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 618a5aedd9bb..94a63b43dd17 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.Process; 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 @@ class CallerValidatorImpl implements CallerValidator { 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 @@ class CallerValidatorImpl implements CallerValidator { 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 b1c25c4f3c61..0044b4b958cb 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.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; @@ -36,8 +35,6 @@ import com.android.internal.infra.AndroidFuture; 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 @@ public interface FutureAppSearchSession extends Closeable { * 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 @@ public interface FutureAppSearchSession extends Closeable { @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; - - 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)); - } - }); - } + interface FutureSearchResults { + + /** + * 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 e78f390a4825..3079d9f51bf3 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.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.SearchResults; import android.app.appsearch.SearchSpec; import android.app.appsearch.SetSchemaRequest; import android.app.appsearch.SetSchemaResponse; @@ -37,6 +39,7 @@ import android.app.appsearch.SetSchemaResponse; 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 @@ public class FutureAppSearchSessionImpl implements FutureAppSearchSession { @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 01e10086a03a..d140258107dc 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 @@ public class MetadataSyncAdapter { * 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 @@ public class MetadataSyncAdapter { ArrayMap<String, ArraySet<String>> packageToFunctionIds = new ArrayMap<>(); FutureSearchResults futureSearchResults = - mFutureAppSearchSession + searchSession .search( "", buildMetadataSearchSpec( @@ -188,4 +401,39 @@ public class MetadataSyncAdapter { 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 1b5b7e875db8..4e36e3ff9188 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -237,6 +237,7 @@ java_library_static { "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 556fae31fd8f..30f3fd2f83a5 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 4da5cfc18089..9398c7a854d4 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.Build; 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 @@ public class AdaptiveAuthService extends SystemService { 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 @@ public class AdaptiveAuthService extends SystemService { 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 @@ public class AdaptiveAuthService extends SystemService { 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 f5a297bfd4f5..6fd281e7003e 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 @@ final class ActivityManagerConstants extends ContentObserver { // 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { updateActivityStartsLoggingEnabled(); updateForegroundServiceStartsLoggingEnabled(); updateForceEnablePssProfiling(); + updateEnableUseAppInfoNotLaunched(); // Read DropboxRateLimiter params from flags. mService.initDropboxRateLimiter(); } @@ -1540,6 +1550,8 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 3f4902db70f5..75e9fadbd917 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub @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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub @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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 4898f1095c58..cb918a045ec6 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 @@ public final class ProcessList { // 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 @@ public final class ProcessList { : 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 @@ public final class ProcessList { 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 439bca0ea36a..a13ce654bb95 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 @@ public class SettingsToPropertiesMapper { 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 @@ public class SettingsToPropertiesMapper { 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 6e8eb7d76108..ab5e2d04cecd 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 430be035737a..314664b0a79d 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 @@ final class AttributedOp { 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 @@ final class AttributedOp { 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 @@ final class AttributedOp { * 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 @@ final class AttributedOp { 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 @@ final class AttributedOp { 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 @@ final class AttributedOp { } 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 2ce4623a19b4..7f161f618618 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_FLAGS_ALL; 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 android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_I 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 android.util.Xml; 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.FileNotFoundException; 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 @@ import java.util.Set; * 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 @@ final class DiscreteRegistry { + 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 @@ final class DiscreteRegistry { 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 @@ final class DiscreteRegistry { if (event == null || event.mAttributionChainId == ATTRIBUTION_CHAIN_ID_NONE || (event.mAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) - == 0) { + == 0) { continue; } @@ -1523,6 +1581,11 @@ final class DiscreteRegistry { 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 @@ final class DiscreteRegistry { 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 fffb1082acb1..6b0253864e2b 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, attributionTag, flags, uidState, accessTime, -1, attributionFlags, - attributionChainId); + attributionChainId, accessType); } } } @@ -510,7 +511,8 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { 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 6daf0d0b7d3b..c3d09bb67452 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 @@ public class AudioService extends IAudioService.Stub 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 b2e95aa1cf28..d3da8dd2cfda 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 @@ flag { 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 8195efe6a56a..456591c3076f 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 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @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 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } ((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 984ad1dd7288..a68451aa1936 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.nio.file.Files; 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 @@ public final class CpuInfoReader { /** 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 @@ public final class CpuInfoReader { 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 @@ public final class CpuInfoReader { 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 @@ public final class CpuInfoReader { 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 @@ public final class CpuInfoReader { } 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 @@ public final class CpuInfoReader { /** * 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 @@ public final class CpuInfoReader { /** * 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 @@ public final class CpuInfoReader { 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 @@ public final class CpuInfoReader { } } - 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 @@ public final class CpuInfoReader { } } } + 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 7ea2c1b02040..88ff7e4103f9 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_ALL; 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 @@ public final class CpuMonitorService extends SystemService { // 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 @@ public final class CpuMonitorService extends SystemService { 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 @@ public final class CpuMonitorService extends SystemService { 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 @@ public final class CpuMonitorService extends SystemService { 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 @@ public final class CpuMonitorService extends SystemService { } } + @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 615db345635c..537fb32523b5 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 d78fdfae266f..dc263c5a6b32 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 @@ public class DisplayDeviceConfig { 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 @@ public class DisplayDeviceConfig { + "\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 9644b1dbb977..3c2167e7a4ef 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 @@ public final class DisplayManagerService extends SystemService { 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 c3faec007552..04573f4b7514 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 5b4e8d51a168..a60434bd574d 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 @@ public class DisplayDeviceConfigUtils { 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 ef4a7984755d..751ab307c400 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 @@ public class HdrBrightnessData { @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 @@ public class HdrBrightnessData { this.minimumHdrPercentOfScreenForHbm = minimumHdrPercentOfScreenForHbm; this.allowInLowPowerMode = allowInLowPowerMode; this.sdrToHdrRatioSpline = sdrToHdrRatioSpline; + this.highestHdrSdrRatio = highestHdrSdrRatio; } @Override @@ -158,6 +162,7 @@ public class HdrBrightnessData { + ", minimumHdrPercentOfScreenForHbm: " + minimumHdrPercentOfScreenForHbm + ", allowInLowPowerMode: " + allowInLowPowerMode + ", sdrToHdrRatioSpline: " + sdrToHdrRatioSpline + + ", highestHdrSdrRatio: " + highestHdrSdrRatio + "} "; } @@ -198,7 +203,9 @@ public class HdrBrightnessData { 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 @@ public class HdrBrightnessData { 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 @@ public class HdrBrightnessData { 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 69b67c87afb9..f600e7fc2946 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 @@ public class DisplayManagerFlags { 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 @@ public class DisplayManagerFlags { } /** + * @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 @@ public class DisplayManagerFlags { 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 da5063acd5a9..9968ba57bba4 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 { } 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 @@ flag { 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 1c85c7f1233c..d116087d5e1c 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 dfcea9f8e46f..ca8ae6e2e68d 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.IInputDevicesChangedListener; 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 @@ public class InputManagerService extends IInputManager.Stub 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 @@ public class InputManagerService extends IInputManager.Stub 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 @@ public class InputManagerService extends IInputManager.Stub // 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 @@ public class InputManagerService extends IInputManager.Stub @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 @@ public class InputManagerService extends IInputManager.Stub 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 @@ public class InputManagerService extends IInputManager.Stub @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 674d3c448c86..bfdb1c1f4ea9 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 @@ final class KeyGestureController { // '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 @@ final class KeyGestureController { } } + @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 @@ final class KeyGestureController { /** 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 @@ final class KeyGestureController { 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 @@ final class KeyGestureController { } } } + + /** 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 1daf4db699aa..609164a48687 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 static android.hardware.input.KeyboardLayoutSelectionResult.layoutSelecti 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.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutCon 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 @@ public final class KeyboardMetricsCollector { @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 486d4afdbf43..cc13e8e5ccc7 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.PixelFormat; 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 com.android.server.input.TouchpadHardwareState; 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 @@ public class TouchpadDebugView extends LinearLayout { 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 @@ public class TouchpadDebugView extends LinearLayout { 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 @@ public class TouchpadDebugView extends LinearLayout { 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 @@ public class TouchpadDebugView extends LinearLayout { 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 @@ public class TouchpadDebugView extends LinearLayout { 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 @@ public class TouchpadDebugView extends LinearLayout { 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 9ba7d0a655f5..67c3621b7c8c 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 @@ import com.android.server.input.TouchpadHardwareState; 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 @@ public class TouchpadVisualizationView extends View { 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 resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X + : mTouchpadHardwareProperties.getResX(); + float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y + : mTouchpadHardwareProperties.getResY(); + + float newTouchMajor = touchpadFingerState.getTouchMajor() * mScaleFactor / resY; + float newTouchMinor = touchpadFingerState.getTouchMinor() * mScaleFactor / resX; - float newTouchMajor = - touchpadFingerState.getTouchMajor() / mTouchpadHardwareProperties.getResX(); - float newTouchMinor = - touchpadFingerState.getTouchMinor() / mTouchpadHardwareProperties.getResY(); + float pressureToOpacity = translateRange(0, maximumPressure, 0, 255, + touchpadFingerState.getPressure()); + mOvalFillPaint.setAlpha((int) pressureToOpacity); - drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle, mOvalPaint); + drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle); } } @@ -101,6 +119,15 @@ public class TouchpadVisualizationView extends View { 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 000000000000..53f1ac668e49 --- /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 7d44ba199119..3780fbd61e79 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.Intent.ACTION_MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTO 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 @@ public class LockSettingsService extends ILockSettings.Stub { } /** + * 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 @@ public class LockSettingsService extends ILockSettings.Stub { 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 f44b85273af6..820c0efcc1cf 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 @@ class RebootEscrowManager { "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 @@ class RebootEscrowManager { /** 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 @@ class RebootEscrowManager { 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 @@ class RebootEscrowManager { 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 cc58f38db65a..3a429b041b3c 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 @@ class SyntheticPasswordManager { .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 000000000000..6818de91c98e --- /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 4fa711262a08..82e00d9b4cbd 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 @@ public class GroupHelper { // 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 e2ec0063c711..ba7d4d218ca5 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.NEWS_ID; 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_NEWS; 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 @@ public class NotificationManagerService extends SystemService { 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 821722b15645..a4fdb758a740 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.PLACEHOLDER_CONVERSATION_ID; 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 @@ public class PreferencesHelper implements RankingConfig { 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 @@ public class PreferencesHelper implements RankingConfig { 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 b03a54ec0cd3..fcc5e9771f94 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 @@ class ZenModeEventLogger { 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 2ada9ae4790d..e9db1b529a63 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { // 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 @@ public class ZenModeHelper { // 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { } 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 9ef2e12e55c5..f6d9dc29d330 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 @@ public class OnDeviceIntelligenceManagerService extends SystemService { 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 023f7655c7a8..ee15bec0d62b 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.graphics.Rect; 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 @@ public class LauncherAppsService extends SystemService { @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 @@ public class LauncherAppsService extends SystemService { 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 @@ public class LauncherAppsService extends SystemService { 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 @@ public class LauncherAppsService extends SystemService { @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 @@ public class LauncherAppsService extends SystemService { } 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 be6fa14952c8..1316df16027f 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 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements 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 045d4db0a1f1..d65e30be9edb 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.IOException; 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 @@ class ShortcutLauncher extends ShortcutPackageItem { */ 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 @@ class ShortcutLauncher extends ShortcutPackageItem { 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 @@ class ShortcutLauncher extends ShortcutPackageItem { } } } + 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 60056eb471d1..c9ad4988f8ca 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 @@ class ShortcutPackage extends ShortcutPackageItem { } 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 a3ff1952205f..ea495c9bee9c 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 @@ import java.util.stream.Collectors; 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 class ShortcutService extends IShortcutService.Stub { 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 @@ public class ShortcutService extends IShortcutService.Stub { && !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 @@ public class ShortcutService extends IShortcutService.Stub { */ 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 4ce01d21903f..935a238bcee7 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 6847a5c699ac..dc6b1644db4d 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 @@ public class ThermalManagerService extends SystemService { 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 f6c3d8ef1249..1346a294b7d8 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 @@ public final class HintManagerService extends SystemService { 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 @@ public final class HintManagerService extends SystemService { @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 @@ public final class HintManagerService extends SystemService { default -> tag = SessionTag.APP; } } - + config.id = -1; Long halSessionPtr = null; if (mConfigCreationSupport.get()) { try { @@ -1109,7 +1111,7 @@ public final class HintManagerService extends SystemService { } } - 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 @@ public final class HintManagerService extends SystemService { } @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 @@ public final class HintManagerService extends SystemService { @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 680b1acedf78..cb8e1a0f35b8 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 @@ public class BatteryStatsImpl extends BatteryStats { 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 @@ public class BatteryStatsImpl extends BatteryStats { } } + 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 cc0a283db6a0..05d29f50085c 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 @@ flag { 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 06a2565da75a..81217014bafe 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.StateTypes.ENABLED_EXCEPT_AL 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 @@ public final class SensorPrivacyService extends SystemService { private final TelephonyManager mTelephonyManager; private final PackageManagerInternal mPackageManagerInternal; private final NotificationManager mNotificationManager; + private final UserManager mUserManager; private CameraPrivacyLightController mCameraPrivacyLightController; @@ -214,6 +216,7 @@ public final class SensorPrivacyService extends SystemService { 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 final class SensorPrivacyService extends SystemService { 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 @@ public final class SensorPrivacyService extends SystemService { @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 @@ public final class SensorPrivacyService extends SystemService { + " 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 @@ public final class SensorPrivacyService extends SystemService { userId = mCurrentUser; } + // Enforce valid calling user on devices that enable visible background users. + enforceValidCallingUser(userId); + if (!canChangeToggleSensorPrivacy(userId, sensor)) { return; } @@ -1151,6 +1174,42 @@ public final class SensorPrivacyService extends SystemService { }); } + // 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 195e91cf5716..49825f16ca94 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 @@ public interface UriGrantsManagerInternal { 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 a581b083f645..3479b6c926da 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.app.ActivityManagerInternal.ALLOW_FULL_ONLY; 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.SYSTEM_UID; 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.os.UserHandle; 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 android.util.Xml; 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements /** 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements } 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements if (clipIntent != null) { NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked( callingUid, targetPkg, clipIntent, mode, needed, targetUserId, - requireContentUriPermissionFromCaller); + requireContentUriPermissionFromCaller, requestHashCode); if (newNeeded != null) { needed = newNeeded; } @@ -706,17 +731,32 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements || 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements } } + 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 class UriGrantsManagerService extends IUriGrantsManager.Stub implements 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 ab4a4d8fc08d..4c1e16c0d14e 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 @@ final class VibrationThread extends Thread { * 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 4fc0b74ecb80..3c478500876f 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.IVibratorStateListener; 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 @@ final class VibratorController { /** 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 @@ final class VibratorController { /** 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 @@ final class VibratorController { * <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 @@ final class VibratorController { * 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); - } - if (mIsVibrating) { - mCurrentAmplitude = 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; + } } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } } @@ -253,13 +279,18 @@ final class VibratorController { * 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 @@ final class VibratorController { * 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 @@ final class VibratorController { return duration; } finally { vendorData.recycle(); + Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } } } @@ -302,14 +335,19 @@ final class VibratorController { * 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 @@ final class VibratorController { * 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; + } + synchronized (mLock) { + long duration = mNativeWrapper.compose(primitives, vibrationId); + if (duration > 0) { + mCurrentAmplitude = -1; + notifyListenerOnVibrating(true); + } + return duration; } - return duration; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } } @@ -345,17 +388,22 @@ final class VibratorController { * @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; + } + synchronized (mLock) { + int braking = mVibratorInfo.getDefaultBraking(); + long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId); + if (duration > 0) { + mCurrentAmplitude = -1; + notifyListenerOnVibrating(true); + } + return duration; } - return duration; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } } @@ -365,10 +413,15 @@ final class VibratorController { * <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 799934af54c0..899f0b121a8d 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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. + 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; } - 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); - } + 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); } + if (result.size() == 0) { + return null; + } + return result; } @Nullable @@ -1580,25 +1575,42 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @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()); - } + 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(); + } - 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(); + 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(); + } + return externalVibration.getScale(); } - return externalVibration.getScale(); } - } - if (!alreadyUnderExternalControl) { + 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); - } - 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(); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } - // 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 f52a74fcdf9f..8c23eaad5521 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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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 class ActivityRecord extends WindowToken implements WindowManagerService.A 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 1822a80c2f95..bc11bacf8200 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 @@ class ActivityStarter { .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 @@ class ActivityStarter { * @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 @@ class ActivityStarter { ? 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 @@ class ActivityStarter { 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 @@ class ActivityStarter { 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 49ca698e36e2..3d5b2732e948 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @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 852ce0401e2c..9c861feba141 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 @@ class AppCompatConfigurationPersister { final File prefFiles = new File(configFolder, letterboxConfigurationFileName); mConfigurationFile = new AtomicFile(prefFiles); mPersisterQueue = persisterQueue; - runWithDiskReadsThreadPolicy(this::readCurrentConfiguration); + readCurrentConfiguration(); } /** @@ -212,6 +209,7 @@ class AppCompatConfigurationPersister { mDefaultTabletopModeReachabilitySupplier.get(); } + @MainThread private void readCurrentConfiguration() { if (!mConfigurationFile.exists()) { useDefaultValue(); @@ -272,20 +270,6 @@ class AppCompatConfigurationPersister { } } - // 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 0646fb74ddfd..dd86a149d0a5 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 @@ class BackNavigationController { 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 @@ class BackNavigationController { 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 dda39a6a12da..e3232e08749e 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 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa } 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 c3db7dd7bfaf..cc6904f9b3af 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.graphics.Rect; 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 @@ public final class DesktopModeBoundsCalculator { 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 e0c0c2c60123..61fbb96882ec 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 @@ package com.android.server.wm; 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 @@ public final class DesktopModeHelper { /** 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 faf6dc667916..bc188959164d 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 @@ public class DimmerAnimationHelper { // 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 @@ public class DimmerAnimationHelper { 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 @@ public class DimmerAnimationHelper { "%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 @@ public class DimmerAnimationHelper { 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 @@ public class DimmerAnimationHelper { /** * 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 @@ public class DimmerAnimationHelper { } } - 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 0daddc01f65e..481ecd3447f1 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 @@ class InsetsStateController { 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 24fb20731c43..22c7e8c98808 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 @@ public abstract class StartingData { * 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 abstract class StartingData { 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 3bb273c55f55..3490b3e12b2a 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 @@ class Task extends TaskFragment { 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 1eeb3ecaf9d6..9d4652957487 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 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** + * 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 459a509a3b3c..33f2dd103c2e 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 class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub | 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 87ce8661c97c..976be4aa3bd4 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } 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 021be5727bf6..1640ad3f1958 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * @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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 dc048ef8c8ec..b92e525ad590 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 @@ import java.util.concurrent.atomic.AtomicBoolean; 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 @@ public final class WindowTracingDataSource extends DataSource<WindowTracingDataS @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 22d6c863fd4f..6e8094ac21d7 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 @@ import java.util.concurrent.atomic.AtomicInteger; 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 2307aced6141..febfb9ff1def 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 @@ static jlong createHintSessionWithConfig(JNIEnv* env, int32_t tgid, int32_t uid, 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 @@ static jlong nativeCreateHintSessionWithConfig(JNIEnv* env, jclass /* clazz */, 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 75db31679a88..b46a6fffbaa9 100644 --- a/services/tests/PackageManagerServiceTests/host/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/Android.bp @@ -95,3 +95,10 @@ test_module_config_host { 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 24e931c3cbb3..f5b0015aff94 100644 --- a/services/tests/PackageManagerServiceTests/server/Android.bp +++ b/services/tests/PackageManagerServiceTests/server/Android.bp @@ -186,3 +186,13 @@ test_module_config { 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 ee20f1a105a4..0568892c3684 100644 --- a/services/tests/VpnTests/Android.bp +++ b/services/tests/VpnTests/Android.bp @@ -43,3 +43,10 @@ android_test { "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 b5cf98697d54..9560ec9990ad 100644 --- a/services/tests/appfunctions/Android.bp +++ b/services/tests/appfunctions/Android.bp @@ -45,8 +45,8 @@ android_test { ], 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 3ebf68937674..6930b3c0699b 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 @@ class MetadataSyncAdapterTest { 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 @@ class MetadataSyncAdapterTest { @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 @@ class MetadataSyncAdapterTest { 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 @@ class MetadataSyncAdapterTest { 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 @@ class MetadataSyncAdapterTest { } @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 @@ class MetadataSyncAdapterTest { } @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 @@ class MetadataSyncAdapterTest { } @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 @@ class MetadataSyncAdapterTest { 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 fe73025e9736..36ea24195789 100644 --- a/services/tests/displayservicetests/Android.bp +++ b/services/tests/displayservicetests/Android.bp @@ -22,6 +22,7 @@ android_test { static_libs: [ "androidx.test.ext.junit", "androidx.test.rules", + "compatibility-device-util-axt", "flag-junit", "frameworks-base-testutils", "junit", @@ -48,6 +49,10 @@ android_test { "automotive-tests", ], + data: [ + ":DisplayManagerTestApp", + ], + certificate: "platform", dxflags: ["--multi-dex"], diff --git a/services/tests/displayservicetests/AndroidManifest.xml b/services/tests/displayservicetests/AndroidManifest.xml index 74260cdd497c..37a34eeb9724 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 2985f98417df..f3697bbffd5c 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 000000000000..90f62577b261 --- /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 76c8e6862211..8b80f85aec00 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; 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.SystemService; 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 @@ public class DisplayManagerServiceTest { } @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 d0aec3b6cef8..bf5a692ef8ca 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.ext.junit.runners.AndroidJUnit4; 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 @@ public final class DisplayPowerControllerTest { private DisplayManagerFlags mDisplayManagerFlagsMock; @Mock private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; + @Mock + private IBatteryStats mMockBatteryStats; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; @@ -204,7 +207,8 @@ public final class DisplayPowerControllerTest { 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 @@ public final class DisplayPowerControllerTest { 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/FromGoneToQuickSettingsShadeTransition.kt b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java index 8a03e29e6377..c4ebbd9fd876 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java @@ -14,14 +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.Edge -import com.android.compose.animation.scene.TransitionBuilder +import android.app.Activity; -fun TransitionBuilder.goneToQuickSettingsShadeTransition( - edge: Edge = Edge.Top, - durationScale: Double = 1.0, -) { - toQuickSettingsShadeTransition(edge, durationScale) -} +/** + * An activity doing nothing + */ +public final class SimpleActivity extends Activity { } diff --git a/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java new file mode 100644 index 000000000000..a719a57efb2d --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java @@ -0,0 +1,24 @@ +/* + * 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 android.app.Activity; + +/** + * 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 c7580331c841..0db7de491f9b 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 @@ fun createHdrBrightnessData( 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 @@ fun createHdrBrightnessData( 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 917c681a0d95..48920d8fbd2a 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 @@ import org.junit.Test class HdrBrightnessDataTest { @Test - fun `test HdrBrightnessData default configuration`() { + fun testHdrBrightnessData_defaultConfiguration() { val displayConfiguration = createDisplayConfiguration { hdrBrightnessConfig( brightnessDecreaseDebounceMillis = "3000", @@ -64,10 +64,11 @@ class HdrBrightnessDataTest { ) 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 @@ class HdrBrightnessDataTest { ) 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 @@ class HdrBrightnessDataTest { 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 @@ class HdrBrightnessDataTest { 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 @@ class HdrBrightnessDataTest { } @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 @@ class HdrBrightnessDataTest { 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 1abc557c8cce..1128f528c778 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.service.dreams.IDreamOverlayClientCallback; 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 @@ public class DreamOverlayServiceTest { mMonitor.onEndDream(); super.onEndDream(); } + + @Override + public void onWakeUp() { + mMonitor.onWakeUp(); + super.onWakeUp(); + } } /** @@ -128,7 +133,6 @@ public class DreamOverlayServiceTest { * 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 @@ public class DreamOverlayServiceTest { // 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 @@ public class DreamOverlayServiceTest { 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 6fc80b836521..c81d6be43223 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -391,3 +391,13 @@ test_module_config { ], 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 000000000000..8b0fab869c1d --- /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 000000000000..40c7bb2f1a2a --- /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 2fbe8aab73d0..3fe038ac4031 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 static com.google.common.truth.Truth.assertWithMessage; 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 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { 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 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { } @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 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { 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 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { } 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 994313f345db..d9e09d8884c7 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.CpuInfo.MISSING_FREQUENCY; 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 @@ public final class CpuMonitorServiceTest { 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 @@ public final class CpuMonitorServiceTest { 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 @@ public final class CpuMonitorServiceTest { } @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 @@ public final class CpuMonitorServiceTest { 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 127d3e8a4136..7ac7aca3fd59 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 @@ android_test { ], 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 aa859422f54f..a31a3fb65700 100644 --- a/services/tests/ondeviceintelligencetests/Android.bp +++ b/services/tests/ondeviceintelligencetests/Android.bp @@ -47,9 +47,9 @@ android_test { ], 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 1692921cdb2d..c8121fc6930a 100644 --- a/services/tests/performancehinttests/Android.bp +++ b/services/tests/performancehinttests/Android.bp @@ -19,7 +19,7 @@ android_test { "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 b2ca991a4aa8..639ae30c00b9 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.app.ActivityManagerInternal; 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 @@ public class HintManagerServiceTest { 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 f74cfae6a81b..c0be8652f303 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 @@ public class AmbientDisplayPowerCalculatorTest { 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 @@ public class AmbientDisplayPowerCalculatorTest { 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 class AmbientDisplayPowerCalculatorTest { 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 @@ public class AmbientDisplayPowerCalculatorTest { 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 afbe9159b66a..2ccb6420bc43 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.Looper; 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.BatteryStatsHistoryIterator; 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 @@ public class BatteryStatsNoteTest { .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 @@ public class BatteryStatsNoteTest { @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 @@ public class BatteryStatsNoteTest { 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 @@ public class BatteryStatsNoteTest { 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 @@ public class BatteryStatsNoteTest { 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 e4ab227a4840..38fc6a9f91dd 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.Intent; 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.ArrayMap; 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.BeforeClass; 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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { ); } - 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 88d4ea75501d..2da98e8b9a61 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 @@ public class ScreenPowerCalculatorTest { 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 @@ public class ScreenPowerCalculatorTest { 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 @@ public class ScreenPowerCalculatorTest { 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 @@ public class ScreenPowerCalculatorTest { 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], 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.updateDisplayEnergyConsumerStatsLocked(new long[]{600_000_000, 500}, screenStates, 80 * MINUTE_IN_MS); @@ -178,8 +181,8 @@ public class ScreenPowerCalculatorTest { 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 class ScreenPowerCalculatorTest { 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 @@ public class ScreenPowerCalculatorTest { 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 @@ public class ScreenPowerCalculatorTest { 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 @@ public class ScreenPowerCalculatorTest { 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, 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.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 12a70387affd..048978ab88a3 100644 --- a/services/tests/selinux/Android.bp +++ b/services/tests/selinux/Android.bp @@ -42,9 +42,9 @@ android_test { "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 895cd1e44ca8..bbe0755b9cc9 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -30,6 +30,7 @@ android_test { "src/**/*.kt", "test-apps/SuspendTestApp/src/**/*.java", + "test-apps/DisplayManagerTestApp/src/**/*.java", ], kotlincflags: [ @@ -90,6 +91,7 @@ android_test { "net_flags_lib", "CtsVirtualDeviceCommonLib", "com_android_server_accessibility_flags_lib", + "locksettings_flags_lib", ], libs: [ @@ -134,6 +136,7 @@ android_test { }, data: [ + ":DisplayManagerTestApp", ":SimpleServiceTestApp1", ":SimpleServiceTestApp2", ":SimpleServiceTestApp3", @@ -278,14 +281,22 @@ java_genrule { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 @@ test_module_config { ], 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 b56af87ee020..5298251b79f7 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 bc3a5ca6f7e6..2ff0c6288ece 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 @@ public class DiscreteAppOpPersistenceTest { 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 @@ public class DiscreteAppOpPersistenceTest { 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 2ba3969bb9e5..87c9db2fe565 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 @@ public abstract class BaseLockSettingsServiceTests { MockLockSettingsContext mContext; LockSettingsStorageTestable mStorage; + LockSettingsStrongAuth mStrongAuth; Resources mResources; FakeGateKeeperService mGateKeeperService; @@ -135,6 +136,7 @@ public abstract class BaseLockSettingsServiceTests { 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 @@ public abstract class BaseLockSettingsServiceTests { 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 93fc071a5bb7..abd39b0bb963 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 class LockSettingsServiceTestable extends LockSettingsService { 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 class LockSettingsServiceTestable extends LockSettingsService { 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 @@ public class LockSettingsServiceTestable extends LockSettingsService { @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 601a01624189..2868e559e02f 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.os.UserHandle; 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 @@ import org.junit.runner.RunWith; @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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { } @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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { } @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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { 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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { } @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 d6f7e21a2069..d071c159d6f5 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.RemoteException; 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.locksettings.ResumeOnRebootServiceProvider.ResumeOnReb 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 @@ public class RebootEscrowManagerTests { 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 @@ public class RebootEscrowManagerTests { private RebootEscrowProviderInterface mRebootEscrowProviderInUse; private ConnectivityManager.NetworkCallback mNetworkCallback; private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer; - private boolean mWaitForInternet; MockInjector( Context context, @@ -159,7 +165,6 @@ public class RebootEscrowManagerTests { super(context, storage, userManagerInternal); mRebootEscrow = rebootEscrow; mServerBased = false; - mWaitForInternet = false; RebootEscrowProviderHalImpl.Injector halInjector = new RebootEscrowProviderHalImpl.Injector() { @Override @@ -185,7 +190,6 @@ public class RebootEscrowManagerTests { super(context, storage, userManagerInternal); mRebootEscrow = null; mServerBased = true; - mWaitForInternet = false; RebootEscrowProviderServerBasedImpl.Injector injector = new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) { @Override @@ -227,15 +231,6 @@ public class RebootEscrowManagerTests { } @Override - public boolean waitForInternet() { - return mWaitForInternet; - } - - public void setWaitForNetwork(boolean waitForNetworkEnabled) { - mWaitForInternet = waitForNetworkEnabled; - } - - @Override public boolean isNetworkConnected() { return false; } @@ -934,10 +929,10 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 000000000000..962ae9be4103 --- /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 000000000000..c0d9d6fd3719 --- /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 000000000000..e9557f84f8fb --- /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 000000000000..07754b201758 --- /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 850d2f7f36a5..a63a38da3740 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -92,3 +92,13 @@ android_test { // 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 196bc47572ba..96ddf8079e17 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.Adjustment.TYPE_NEWS; 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 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @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 559c32413d70..1905ae4aec4b 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 @@ public class PreferencesHelperTest extends UiServiceTestCase { .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 f8ff1f45e89c..efcf027a0b90 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 @@ public class ZenModeConfigTest extends UiServiceTestCase { 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 baa633f16f67..39a9d30e7a92 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { // ... 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { // ... 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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 c706d5200443..c176658da847 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 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { 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 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { 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 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { 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 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { 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 5a3ae769ef62..a48813d775d1 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 com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM; 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.graphics.Rect; 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 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { new CameraCompatFreeformPolicy(mDisplayContent, cameraStateMonitor, mActivityRefresher); + setDisplayRotation(Surface.ROTATION_90); mCameraCompatFreeformPolicy.start(); cameraStateMonitor.startListeningToCameraState(); } @@ -162,17 +171,49 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { } @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 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { 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 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { 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 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { 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 2f2b4732f1eb..b7aa730443e7 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 androidx.test.filters.SmallTest; 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 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase { } 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 71cfbfd94a53..08622e68629a 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 @@ public class SystemServicesTestRule implements TestRule { private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners = new ArrayList<>(); + private AppCompatConfiguration mAppCompat; private Description mDescription; private Context mContext; private StaticMockitoSession mMockitoSession; @@ -379,6 +380,11 @@ public class SystemServicesTestRule implements TestRule { 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 @@ public class SystemServicesTestRule implements TestRule { 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 45082d280587..7ff2e50926a5 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 static org.mockito.Mockito.never; 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 class TaskTests extends WindowTestsBase { 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 e11df9863efb..877f65c544da 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 android.view.DisplayInfo; 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 @@ public final class TestDisplayWindowSettingsProvider extends DisplayWindowSettin 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 @@ public final class TestDisplayWindowSettingsProvider extends DisplayWindowSettin 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 5a54af10888f..2d5e5dacc217 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.ArgumentMatchers.eq; 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.content.res.Configuration; 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 androidx.test.filters.SmallTest; 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 @@ public class WindowStateTests extends WindowTestsBase { 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 c45b99d9dc23..410499916be9 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 org.mockito.ArgumentMatchers.eq; 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.tools.traces.monitors.PerfettoTraceMonitor; 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 PerfettoTraceMonitor mTraceMonitor; - private ResultWriter mWriter; + private static final String TEST_DATA_SOURCE_NAME = "android.windowmanager.test"; - @Before - public void setUp() throws Exception { - mWmMock = Mockito.mock(WindowManagerService.class); - Mockito.doNothing().when(mWmMock).dumpDebugLocked(Mockito.any(), Mockito.anyInt()); + private static WindowManagerService sWmMock; + private static Choreographer sChoreographer; + private static WindowTracing sWindowTracing; - mChoreographer = Mockito.mock(Choreographer.class); + private PerfettoTraceMonitor mTraceMonitor; - mWindowTracing = new WindowTracingPerfetto(mWmMock, mChoreographer, - new WindowManagerGlobalLock()); + @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(); + } - mWriter = new ResultWriter() - .forScenario(new ScenarioBuilder() - .forClass(createTempFile("temp", "").getName()).build()) - .withOutputDir(createTempDirectory("temp").toFile()) - .setRunComplete(); + @Before + 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 579fda320e9a..a0f01bded764 100644 --- a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl +++ b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl @@ -50,4 +50,11 @@ oneway interface ISatelliteTransmissionUpdateCallback { * 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 284e2bd8aa6c..90dae3be058c 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -1220,6 +1220,12 @@ public final class SatelliteManager { () -> 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 d8bd66284fb0..046ae5fdeb3c 100644 --- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java @@ -75,4 +75,13 @@ public interface SatelliteTransmissionUpdateCallback { 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 67825d2df361..3753b23966d2 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.FlickerBuilder 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 @@ import org.junit.runners.Parameterized * 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 4a675be65549..0bcd2f334c32 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.WindowManagerStateHelper 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 @@ constructor( * 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 @@ constructor( * 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 @@ constructor( .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 917aec1e809d..939ba81a47ea 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 a05d08ccceba..914adc40194d 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 000000000000..1a9112b97301 --- /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 000000000000..df4f9fb4e1df --- /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 000000000000..072341dcefae --- /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 14aac6637d4f..ca9de6000a5a 100644 --- a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt +++ b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt @@ -53,12 +53,12 @@ class KeyGestureEventListenerTest { 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 @@ class KeyGestureEventListenerTest { } 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 3f611e0ead53..e12679742224 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 @@ package com.android.server.input 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 @@ import org.mockito.junit.MockitoJUnit 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 @@ class KeyGestureControllerTests { // 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 99e04cce64f4..071968679b9b 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 @@ public class TouchpadDebugViewTest { 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 d32cedb24a36..cd6ab30d8678 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 @@ class AnrTest { 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 000000000000..d54e3470d9c4 --- /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 000000000000..aa73c397a663 --- /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 2909e66b53be..331a21a0215b 100644 --- a/tests/UsbManagerTests/Android.bp +++ b/tests/UsbManagerTests/Android.bp @@ -44,7 +44,7 @@ android_test { "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 d80eaeb32c1e..1a08f998442d 100644 --- a/tests/permission/Android.bp +++ b/tests/permission/Android.bp @@ -25,3 +25,10 @@ android_test { 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 ea77b8de97aa..4920f7b41e3f 100644 --- a/tools/hoststubgen/hoststubgen/Android.bp +++ b/tools/hoststubgen/hoststubgen/Android.bp @@ -5,6 +5,10 @@ package { // 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 f5af99ec39ac..b79563f740ee 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 @@ fun getHelperMethodFix( 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 5c6469706e18..af753e5963a3 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.IssueRegistry 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 @@ class AndroidFrameworkIssueRegistry : IssueRegistry() { 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 bce848a2e3a7..000000000000 --- 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 28eab8f62e74..290e7be9f6c4 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.IssueRegistry 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 @@ class AndroidGlobalIssueRegistry : IssueRegistry() { 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 8777712b0f04..675a59e6ae3e 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 @@ package com.google.android.lint.aidl * 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 @@ val exemptAidlInterfaces = setOf( "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 index 6b50cfd9e5ab..d44c271e734c 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 @@ class PermissionAnnotationDetector : AidlImplementationDetector() { 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 @@ class PermissionAnnotationDetector : AidlImplementationDetector() { 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 000000000000..92d0829911bf --- /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 6ad223c87a29..57c2e5aa9767 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 @@ import org.jetbrains.uast.UMethod */ 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 @@ class ExemptAidlInterfacesGenerator : AidlImplementationDetector() { 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 aca25eb8f603..a9e63289ee93 100644 --- a/tools/systemfeatures/Android.bp +++ b/tools/systemfeatures/Android.bp @@ -5,6 +5,7 @@ package { // 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 @@ java_binary_host { 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 @@ genrule { 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 @@ java_test_host { "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 e537ffcb56bd..5df453deaf2a 100644 --- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt +++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt @@ -142,6 +142,10 @@ object SystemFeaturesGenerator { // 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 @@ object SystemFeaturesGenerator { 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 @@ object SystemFeaturesGenerator { 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 000000000000..724639b52d23 --- /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 000000000000..59c5b4e8fecb --- /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 000000000000..6f897591e48f --- /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 000000000000..2111d564f28d --- /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 000000000000..c2492542bc37 --- /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 index 630bc0771a01..630bc0771a01 100644 --- a/tools/systemfeatures/tests/Context.java +++ b/tools/systemfeatures/tests/src/Context.java diff --git a/tools/systemfeatures/tests/PackageManager.java b/tools/systemfeatures/tests/src/PackageManager.java index db670482065a..db670482065a 100644 --- a/tools/systemfeatures/tests/PackageManager.java +++ b/tools/systemfeatures/tests/src/PackageManager.java diff --git a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java index 6dfd244a807b..6dfd244a807b 100644 --- a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java +++ b/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 000000000000..e3a5841d8abb --- /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> |